2016-individuals
Let’s have a look at what’s inside data_nes$data_2016:
# list structure
str(data_nes$year_2016, max.level = 1, give.attr = F, no.list = T)
## $ ind_3449:Classes 'data.table' and 'data.frame': 384 obs. of 23 variables:
## $ ind_3450:Classes 'data.table' and 'data.frame': 253 obs. of 23 variables:
## $ ind_3456:Classes 'data.table' and 'data.frame': 253 obs. of 23 variables:
## $ ind_3457:Classes 'data.table' and 'data.frame': 253 obs. of 23 variables:
## $ ind_3460:Classes 'data.table' and 'data.frame': 253 obs. of 23 variables:
## $ ind_3463:Classes 'data.table' and 'data.frame': 213 obs. of 23 variables:
A list of 6 data.frames, one for each seal
For convenience, we aggregate all 6 individuals into one dataset.
# combine all individuals
data_2016 <- rbindlist(data_nes$year_2016, use.name = TRUE, idcol = TRUE)
# display
DT::datatable(data_2016[sample.int(.N, 100), ], options = list(scrollX = T))
Table 1: Sample of 100 random rows from data_2016
Summary
# raw_data
data_2016[, .(nb_days_recorded = uniqueN(as.Date(date)), max_depth = max(maxpress_dbars),
sst_mean = mean(sst2_c), sst_sd = sd(sst2_c)), by = .id] %>%
sable(caption = "Summary diving information relative to each 2016 individual",
digits = 2)
Table 2: Summary diving information relative to each 2016 individual
|
.id
|
nb_days_recorded
|
max_depth
|
sst_mean
|
sst_sd
|
|
ind_3449
|
384
|
1118.81
|
26.54
|
129.91
|
|
ind_3450
|
253
|
954.81
|
130.29
|
367.69
|
|
ind_3456
|
253
|
697.63
|
125.24
|
360.39
|
|
ind_3457
|
253
|
572.94
|
135.56
|
374.71
|
|
ind_3460
|
253
|
832.25
|
65.24
|
249.12
|
|
ind_3463
|
213
|
648.81
|
212.19
|
462.88
|
Well, it seems that sst is a bit odd. Let’s have a look at its distribution.
ggplot(data_2016, aes(x = sst2_c, fill = .id)) + geom_histogram(show.legend = FALSE) +
facet_wrap(.id ~ .) + theme_jjo()
Let’s remove any data with a sst2_c > 500.
data_2016_filter <- data_2016[sst2_c < 500, ]
ggplot(data_2016_filter, aes(x = sst2_c, fill = .id)) + geom_histogram(show.legend = FALSE) +
facet_wrap(.id ~ .) + theme_jjo()
Well, that seems to be much better! In the process of filtering out odd values, we removed 116 rows this way:
# nbrow removed
data_2016[sst2_c > 500, .(nb_row_removed = .N), by = .id] %>%
sable(caption = "# of rows removed by 2016-individuals")
Table 3: # of rows removed by 2016-individuals
|
.id
|
nb_row_removed
|
|
ind_3449
|
4
|
|
ind_3450
|
23
|
|
ind_3456
|
22
|
|
ind_3457
|
24
|
|
ind_3460
|
10
|
|
ind_3463
|
33
|
# max depth
ggplot(data_2016, aes(y = -maxpress_dbars, x = as.Date(date), col = .id)) + geom_path(show.legend = FALSE) +
geom_point(data = data_2016[sst2_c > 500, ], col = "black") + scale_x_date(date_labels = "%m/%Y") +
labs(y = "Pressure (dbar)", x = "Date") + facet_wrap(.id ~ .) + theme_jjo() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
Well this latter plot highlights several points:
- most of the outliers occur while animals spend the whole day at the surface (or on the ground), probably resting, so essentially at the beginning and the end of each track
- we can already see that
ind_3449 seems to have return ashore twice during his track
Let’s see if we can double check that, using a map.
# interactive map
leaflet() %>%
setView(lng = -122, lat = 38, zoom = 2) %>%
addTiles() %>%
addPolylines(lat = data_2016[.id == "ind_3449", latitude_degs], lng = data_2016[.id ==
"ind_3449", longitude_degs], weight = 2) %>%
addCircleMarkers(lat = data_2016[.id == "ind_3449" & sst2_c > 500, latitude_degs],
lng = data_2016[.id == "ind_3449" & sst2_c > 500, longitude_degs], radius = 3,
stroke = FALSE, color = "red", fillOpacity = 1)
… these coordinates seem weird !
# summary of the coordinates by individuals
data_2016[, .(.id, longitude_degs, latitude_degs)] %>%
tbl_summary(by = .id) %>%
modify_caption("Summary of `longitude_degree` and `latitude_degree`")
Table 4: Summary of longitude_degree and latitude_degree
| Characteristic |
ind_3449, N = 384 |
ind_3450, N = 253 |
ind_3456, N = 253 |
ind_3457, N = 253 |
ind_3460, N = 253 |
ind_3463, N = 213 |
| longitude_degs |
-119 (-132, -69) |
-124 (-144, -99) |
-112 (-134, -6) |
-122 (-132, -97) |
-122 (-144, -85) |
-121 (-134, -93) |
| latitude_degs |
39 (-67, 68) |
60 (-63, 68) |
56 (-63, 68) |
44 (-63, 68) |
59 (-63, 68) |
63 (42, 72) |
# distribution coordinates
ggplot(data = melt(data_2016[, .(Longitude = longitude_degs, Latitude = latitude_degs,
.id)], id.vars = ".id", value.name = "Coordinate"), aes(x = Coordinate, fill = .id)) +
geom_histogram(show.legend = F) + facet_grid(variable ~ .id) + theme_jjo()
There is definitely something wrong with these coordinates (five seals would have crossed the equator…), but the representation of the track can also be improved! Here are the some points to explore:
- For
longitude a part of the data seems to have a wrong sign, resulting in these distribution, that appear to be cut off
- For
latitude, well this is ensure but maybe the same problem occurs
Let’s try to play on coordinates’ sign to see if we can display something that makes more sense.
# interactive map
leaflet() %>%
setView(lng = -122, lat = 50, zoom = 3) %>%
addTiles() %>%
addPolylines(lat = data_2016[.id == "ind_3449", abs(latitude_degs)], lng = data_2016[.id ==
"ind_3449", -abs(longitude_degs)], weight = 2)
I’ll better ask Roxanne!
Missing values
# build dataset to check for missing values
dataPlot <- melt(data_2016_filter[, .(.id, is.na(.SD)), .SDcol = -c(".id", "rec#",
"date", "time")])
# add the id of rows
dataPlot[, `:=`(id_row, c(1:.N)), by = c("variable", ".id")]
# plot
ggplot(dataPlot, aes(x = variable, y = id_row, fill = value)) + geom_tile() + labs(x = "Attributes",
y = "Rows") + scale_fill_manual(values = c("white", "black"), labels = c("Real",
"Missing")) + facet_wrap(.id ~ ., scales = "free_y") + theme_jjo() + theme(legend.position = "top",
axis.text.x = element_text(angle = 45, hjust = 1), legend.key = element_rect(colour = "black"))
2018-individuals
Let’s have a look at what’s inside data_nes$data_2018:
# list structure
str(data_nes$year_2018, max.level = 1, give.attr = F, no.list = T)
## $ ind_2018070:Classes 'data.table' and 'data.frame': 22393 obs. of 46 variables:
## $ ind_2018072:Classes 'data.table' and 'data.frame': 29921 obs. of 46 variables:
## $ ind_2018074:Classes 'data.table' and 'data.frame': 38608 obs. of 46 variables:
## $ ind_2018080:Classes 'data.table' and 'data.frame': 19028 obs. of 46 variables:
A list of 4 data.frames, one for each seal
For convenience, we aggregate all 4 individuals into one dataset.
# combine all individuals
data_2018 <- rbindlist(data_nes$year_2018)
# display
DT::datatable(data_2018[sample.int(.N, 100), ], options = list(scrollX = T))
Table 1: Sample of 100 random rows from data_2018
Summary
# raw_data
data_2018[, .(nb_days_recorded = uniqueN(as.Date(date)), nb_dives = .N, maxdepth_mean = mean(maxdepth),
dduration_mean = mean(dduration), botttime_mean = mean(botttime), pdi_mean = mean(pdi,
na.rm = T)), by = .id] %>%
sable(caption = "Summary diving information relative to each 2018 individual",
digits = 2)
Table 5: Summary diving information relative to each 2018 individual
|
.id
|
nb_days_recorded
|
nb_dives
|
maxdepth_mean
|
dduration_mean
|
botttime_mean
|
pdi_mean
|
|
ind_2018070
|
232
|
22393
|
305.52
|
783.27
|
243.22
|
109.55
|
|
ind_2018072
|
341
|
29921
|
357.86
|
876.96
|
278.02
|
104.90
|
|
ind_2018074
|
372
|
38608
|
250.67
|
686.25
|
291.89
|
302.77
|
|
ind_2018080
|
215
|
19028
|
296.50
|
867.69
|
339.90
|
103.51
|
Very nice dataset :)
Some explanatory plots
Missing values
# build dataset to check for missing values
dataPlot <- melt(data_2018[, .(.id, is.na(.SD)), .SDcol = -c(".id", "divenumber",
"year", "month", "day", "hour", "min", "sec", "juldate", "divetype", "date",
"phase", "lat", "lon")])
# add the id of rows
dataPlot[, `:=`(id_row, c(1:.N)), by = c("variable", ".id")]
# plot
ggplot(dataPlot, aes(x = variable, y = id_row, fill = value)) + geom_tile() + labs(x = "Attributes",
y = "Rows") + scale_fill_manual(values = c("white", "black"), labels = c("Real",
"Missing")) + facet_wrap(.id ~ ., scales = "free_y") + theme_jjo() + theme(legend.position = "top",
axis.text.x = element_text(angle = 45, hjust = 1), legend.key = element_rect(colour = "black"))
So far so good, only few variables seems to have missing values:
# table with percent
table_inter <- data_2018[, lapply(.SD, function(x) {
round(length(x[is.na(x)]) * 100/length(x), 1)
}), .SDcol = -c(".id", "divenumber", "year", "month", "day", "hour", "min", "sec",
"juldate", "divetype", "date", "phase", "lat", "lon")]
# find which are different from 0
cond_inter <- sapply(table_inter, function(x) {
x == 0
})
# display the percentages that are over 0
table_inter[, `:=`(which(cond_inter), NULL)] %>%
sable(caption = "Percentage of missing values per columns having missing values!") %>%
scroll_box(width = "100%")
Table 6: Percentage of missing values per columns having missing values!
|
lightatsurf
|
lattenuation
|
euphoticdepth
|
thermoclinedepth
|
driftrate
|
benthicdivevertrate
|
cornerindex
|
foragingindex
|
verticalspeed90perc
|
verticalspeed95perc
|
|
26.3
|
89
|
62.6
|
1.3
|
0.5
|
22.7
|
75.8
|
0.5
|
0.1
|
0.1
|
Outliers
Ok, let’s have a look at all the data. But first, we have to remove outliers. Some of them are quiet easy to spot looking at the distribution of dive duration:
Before
ggplot(data_2018[, .SD][, `:=`(state, "Before")], aes(x = dduration, fill = .id)) +
geom_histogram(show.legend = FALSE) + geom_vline(xintercept = 3000, linetype = "longdash") +
facet_grid(state ~ .id, scales = "free") + labs(y = "# of dives", x = "Dive duration (s)") +
theme_jjo()
After
ggplot(data_2018[dduration < 3000, ][][, `:=`(state, "After")], aes(x = dduration,
fill = .id)) + geom_histogram(show.legend = FALSE) + geom_vline(xintercept = 3000,
linetype = "longdash") + facet_grid(state ~ .id, scales = "free") + labs(x = "# of dives",
y = "Dive duration (s)") + theme_jjo()
It seems much better, so let’s remove any rows with dduration > 3000 sec.
# filter data
data_2018_filter <- data_2018[dduration < 3000, ]
# nbrow removed
data_2018[dduration >= 3000, .(nb_row_removed = .N), by = .id] %>%
sable(caption = "# of rows removed by 2018-individuals")
Table 7: # of rows removed by 2018-individuals
|
.id
|
nb_row_removed
|
|
ind_2018070
|
3
|
|
ind_2018072
|
1
|
|
ind_2018074
|
33
|
Check day and night
Light levels
# let's first average `lightatsurf` by individuals, day since departure and
# hour
dataPlot <- data_2018[, .(lightatsurf = median(lightatsurf)), by = .(.id, day_departure,
date = as.Date(date), hour)]
# display the result
ggplot(dataPlot, aes(x = day_departure, y = hour, fill = lightatsurf)) + geom_tile() +
facet_grid(.id ~ .) + theme_jjo() + labs(x = "# of days since departure", y = "Hour",
fill = "Light level at the surface") + theme(legend.position = c("bottom"))
Day and night detection
# let's first average `lightatsurf` by individuals, day since departure and
# hour
dataPlot <- data_2018[, .(lightatsurf = median(lightatsurf)), by = .(.id, day_departure,
date = as.Date(date), hour, phase)]
# display the result
ggplot(dataPlot, aes(x = day_departure, y = hour, fill = phase)) + geom_tile() +
facet_grid(.id ~ .) + theme_jjo() + labs(x = "# of days since departure", y = "Hour",
fill = "Day time and night time as detected by the `cal_phase_day` function") +
theme(legend.position = c("bottom"))
All Variables
names_display <- names(data_2018_filter[, -c(".id", "date", "divenumber", "year",
"month", "day", "hour", "min", "sec", "juldate", "divetype", "euphoticdepth",
"thermoclinedepth", "day_departure", "phase", "lat", "lon")])
for (i in names_display) {
cat("#####", i, "{.unlisted .unnumbered} \n")
if (i == "maxdepth") {
print(ggplot() + geom_point(data = data_2018_filter[, .(.id, date, thermoclinedepth)],
aes(x = as.Date(date), y = -thermoclinedepth, colour = "Thermocline (m)"),
alpha = 0.2, size = 0.5) + geom_point(data = data_2018_filter[, .(.id,
date, euphoticdepth)], aes(x = as.Date(date), y = -euphoticdepth, colour = "Euphotic (m)"),
alpha = 0.2, size = 0.5) + scale_colour_manual(values = c(`Thermocline (m)` = "red",
`Euphotic (m)` = "black"), name = "Zone") + new_scale_color() + geom_point(data = melt(data_2018_filter[,
.(.id, date, get(i))], id.vars = c(".id", "date")), aes(x = as.Date(date),
y = -value, col = .id), alpha = 1/10, size = 0.5, show.legend = FALSE) +
facet_wrap(. ~ .id, scales = "free") + scale_x_date(date_labels = "%m/%Y") +
labs(x = "Date", y = "Maximum Depth (m)") + theme_jjo() + theme(axis.text.x = element_text(angle = 45,
hjust = 1), legend.position = "bottom"))
cat("<blockquote> Considering `ind_2018074` has slightly different values than other individuals for the thermocline depth, it would be interesting to see where the animal went. </blockquote>")
} else if (i == "driftrate") {
print(ggplot(data = melt(data_2018_filter[, .(.id, date, get(i), divetype)],
id.vars = c(".id", "date", "divetype")), aes(x = as.Date(date), y = value,
col = divetype)) + geom_point(alpha = 1/10, size = 0.5) + facet_wrap(. ~
.id, scales = "free") + scale_x_date(date_labels = "%m/%Y") + labs(x = "Date",
y = "Drift Rate 'm/s", col = "Dive Type") + theme_jjo() + theme(axis.text.x = element_text(angle = 45,
hjust = 1), legend.position = "bottom") + guides(colour = guide_legend(override.aes = list(size = 7,
alpha = 1))))
} else {
print(ggplot(data = melt(data_2018_filter[, .(.id, date, get(i))], id.vars = c(".id",
"date")), aes(x = as.Date(date), y = value, col = .id)) + geom_point(show.legend = FALSE,
alpha = 1/10, size = 0.5) + facet_wrap(. ~ .id, scales = "free") + scale_x_date(date_labels = "%m/%Y") +
labs(x = "Date", y = i) + theme_jjo() + theme(axis.text.x = element_text(angle = 45,
hjust = 1)))
}
cat("\n \n")
}
maxdepth
Considering ind_2018074 has slightly different values than other individuals for the thermocline depth, it would be interesting to see where the animal went.
dduration

botttime

desctime

descrate

asctime

ascrate

pdi

dwigglesdesc

dwigglesbott

dwigglesasc

totvertdistbot

bottrange

efficiency

idz

lightatbott

lwiggles

lightatsurf

lattenuation

tempatsurf

tempatbott

driftdiveindex

driftrate

benthicdiveindex

benthicdivevertrate

cornerindex

foragingindex

verticalspeed90perc

verticalspeed95perc

Few questions, that I should look into it:
- is the bimodal distribution of
dduration, desctime due to nycthemeral migration?
- is the bimodal distribution of
descrate (especially for ind2018070 and ind_2018072) due to drift dive?
- is
lightatbott could be used to identify bioluminescence, cause it seems there is a lot going on at the bottom?
- are the variations observed for
lightatsurf is due to moon cycle?
- not sure why is there a bimodal distribution of
tempatbott!
drifrate that one is awesome! Thanks to divetype we can clearly see a pattern of how driftrate (and so buoyancy) change according time.
- the bimodal distribution of
verticalspeed90 and verticalspeed95 should be due to drift dive.
# same plot with a colored for the phase of the day
for (i in names_display) {
cat("#####", i, "{-} \n")
print(ggplot(data = melt(data_2018_filter[, .(.id, date, get(i), phase)], id.vars = c(".id",
"date", "phase")), aes(x = as.Date(date), y = value, col = phase)) + geom_point(alpha = 1/10,
size = 0.5) + facet_wrap(. ~ .id, scales = "free") + scale_x_date(date_labels = "%m/%Y") +
labs(x = "Date", y = i) + theme_jjo() + theme(axis.text.x = element_text(angle = 45,
hjust = 1), legend.position = "bottom") + guides(colour = guide_legend(override.aes = list(size = 7,
alpha = 1))))
cat("\n \n")
}
maxdepth

dduration

botttime

desctime

descrate

asctime

ascrate

pdi

dwigglesdesc

dwigglesbott

dwigglesasc

totvertdistbot

bottrange

efficiency

idz

lightatbott

lwiggles

lightatsurf

lattenuation

tempatsurf

tempatbott

driftdiveindex

driftrate

benthicdiveindex

benthicdivevertrate

cornerindex

foragingindex

verticalspeed90perc

verticalspeed95perc

All Variables during the first month
for (i in names_display) {
cat("#####", i, "{.unlisted .unnumbered} \n")
if (i == "maxdepth") {
print(ggplot() + geom_point(data = data_2018_filter[day_departure < 32, .(.id,
day_departure, thermoclinedepth)], aes(x = day_departure, y = -thermoclinedepth,
colour = "Thermocline (m)", group = day_departure), alpha = 0.2, size = 0.5) +
geom_point(data = data_2018_filter[day_departure < 32, .(.id, day_departure,
euphoticdepth)], aes(x = day_departure, y = -euphoticdepth, colour = "Euphotic (m)",
group = day_departure), alpha = 0.2, size = 0.5) + scale_colour_manual(values = c(`Thermocline (m)` = "red",
`Euphotic (m)` = "black"), name = "Zone") + new_scale_color() + geom_boxplot(data = melt(data_2018_filter[day_departure <
32, .(.id, day_departure, get(i))], id.vars = c(".id", "day_departure")),
aes(x = day_departure, y = -value, col = .id, group = day_departure),
alpha = 1/10, size = 0.5, show.legend = FALSE) + facet_wrap(. ~ .id,
scales = "free") + labs(x = "# days since departure", y = "Maximum Depth (m)") +
theme_jjo() + theme(legend.position = "bottom"))
} else {
print(ggplot(data = melt(data_2018_filter[day_departure < 32, .(.id, day_departure,
get(i))], id.vars = c(".id", "day_departure")), aes(x = day_departure,
y = value, color = .id, group = day_departure)) + geom_boxplot(show.legend = FALSE,
alpha = 1/10, size = 0.5) + facet_wrap(. ~ .id, scales = "free") + labs(x = "# days since departure",
y = i) + theme_jjo())
}
cat("\n \n")
}
maxdepth

dduration

botttime

desctime

descrate

asctime

ascrate

pdi

dwigglesdesc

dwigglesbott

dwigglesasc

totvertdistbot

bottrange

efficiency

idz

lightatbott

lwiggles

lightatsurf

lattenuation

tempatsurf

tempatbott

driftdiveindex

driftrate

benthicdiveindex

benthicdivevertrate

cornerindex

foragingindex

verticalspeed90perc

verticalspeed95perc

for (i in names_display) {
cat("#####", i, "{.unlisted .unnumbered} \n")
print(ggplot(data = melt(data_2018_filter[day_departure < 32, .(.id, day_departure,
get(i), phase)], id.vars = c(".id", "day_departure", "phase")), aes(x = day_departure,
y = value, color = phase, group = interaction(day_departure, phase), )) +
geom_boxplot(alpha = 1/10, size = 0.5) + facet_wrap(. ~ .id, scales = "free") +
labs(x = "# days since departure", y = i) + theme_jjo() + theme(legend.position = "bottom"))
cat("\n \n")
}
maxdepth

dduration

botttime

desctime

descrate

asctime

ascrate

pdi

dwigglesdesc

dwigglesbott

dwigglesasc

totvertdistbot

bottrange

efficiency

idz

lightatbott

lwiggles

lightatsurf

lattenuation

tempatsurf

tempatbott

driftdiveindex

driftrate

benthicdiveindex

benthicdivevertrate

cornerindex

foragingindex

verticalspeed90perc

verticalspeed95perc

Correlation
Can we find nice correlation?
# compute correlation
corr_2018 <- round(cor(data_2018_filter[, names_display, with = F], use = "pairwise.complete.obs"),
1)
# replace NA value by 0
corr_2018[is.na(corr_2018)] <- 0
# compute p_values
corr_p_2018 <- cor_pmat(data_2018_filter[, names_display, with = F])
# replace NA value by 0
corr_p_2018[is.na(corr_p_2018)] <- 1
# display
ggcorrplot(corr_2018, p.mat = corr_p_2018, hc.order = TRUE, method = "circle", type = "lower",
ggtheme = theme_jjo(), sig.level = 0.05, colors = c("#00AFBB", "#E7B800", "#FC4E07"))
Another way to see it:
# flatten correlation matrix
cor_result_2018 <- flat_cor_mat(corr_2018, corr_p_2018)
# keep only the one above .7
cor_result_2018[cor >= 0.7, ][order(-abs(cor))] %>%
sable(caption = "Pairwise correlation above 0.75 and associated p-values")
Table 8: Pairwise correlation above 0.75 and associated p-values
|
row
|
column
|
cor
|
p
|
|
verticalspeed90perc
|
verticalspeed95perc
|
1.0
|
0
|
|
maxdepth
|
asctime
|
0.8
|
0
|
|
botttime
|
efficiency
|
0.8
|
0
|
|
dwigglesbott
|
foragingindex
|
0.8
|
0
|
|
maxdepth
|
dduration
|
0.7
|
0
|
|
maxdepth
|
desctime
|
0.7
|
0
|
|
dduration
|
desctime
|
0.7
|
0
|
|
dduration
|
asctime
|
0.7
|
0
|
|
totvertdistbot
|
bottrange
|
0.7
|
0
|
|
totvertdistbot
|
verticalspeed90perc
|
0.7
|
0
|
|
totvertdistbot
|
verticalspeed95perc
|
0.7
|
0
|
I guess nothing unexpected here, I’ll have to check with Patrick about the efficiency ;)
Dive Type
# dataset to plot proportional area plot
data_2018_filter[, `:=`(sum_id, .N), by = .(.id, day_departure)][, `:=`(sum_id_days,
.N), by = .(.id, day_departure, divetype)][, `:=`(prop, sum_id_days/sum_id)]
dataPlot <- unique(data_2018_filter[, .(prop, .id, divetype, day_departure)])
# area plot
ggplot(dataPlot, aes(x = as.numeric(day_departure), y = prop, fill = as.character(divetype))) +
geom_area(alpha = 0.6, size = 1) + facet_wrap(.id ~ ., scales = "free") + theme_jjo() +
theme(legend.position = "bottom") + labs(x = "# of days since departure", y = "Proportion of dives",
fill = "Dive types")
Dive duration vs. Maximum depth
Colored by ID
# plot
ggplot(data = data_2018_filter, aes(y = dduration, x = maxdepth, col = .id)) + geom_point(size = 0.5,
alpha = 0.1, show.legend = FALSE) + facet_wrap(.id ~ .) + labs(x = "Maximum depth (m)",
y = "Dive duration (s)") + theme_jjo()
Colored by Dive Type
# plot
ggplot(data = data_2018_filter, aes(y = dduration, x = maxdepth, col = divetype)) +
geom_point(size = 0.5, alpha = 0.1) + facet_wrap(.id ~ .) + guides(colour = guide_legend(override.aes = list(size = 5,
alpha = 1))) + labs(x = "Maximum depth (m)", y = "Dive duration (s)") + theme_jjo() +
theme(legend.position = "bottom")
Colored by # days since departure
# plot
ggplot(data = data_2018_filter[, `:=`(prop_track, (day_departure * 100)/max(day_departure)),
by = .id], aes(y = dduration, x = maxdepth, col = prop_track)) + geom_point(size = 0.5,
alpha = 0.1) + facet_wrap(.id ~ .) + labs(x = "Maximum depth (m)", y = "Dive duration (s)",
col = "Proportion of completed track (%)") + scale_color_continuous(type = "viridis") +
theme_jjo() + theme(legend.position = "bottom")
Colored by phases of day
# plot
ggplot(data = data_2018_filter, aes(y = dduration, x = maxdepth, col = phase)) +
geom_point(size = 0.5, alpha = 0.1) + facet_wrap(.id ~ .) + guides(colour = guide_legend(override.aes = list(size = 5,
alpha = 1))) + labs(x = "Maximum depth (m)", y = "Dive duration (s)", col = "Phases of the day") +
theme_jjo() + theme(legend.position = "bottom")
There seems to be a patch for high depths (especially visible for ind2018070), but I don’t know what it could be linked to…
Drift Rate
In the following graphs:
driftrate is calculated using only divetype == "2: drift"
- whereas all the others variables are calculated all dives considered
# build dataset
dataPlot <- data_2018_filter[divetype == "2: drift",
# median drift rate for drift dive
.(driftrate = median(driftrate, na.rm = T)),
by = .(.id, day_departure)
][data_2018_filter[,
.(
# median dive duration all dives considered
dduration = median(dduration, na.rm = T),
# median max depth all dives considered
maxdepth = median(maxdepth, na.rm = T),
# median bottom dives all dives considered
botttime = median(botttime, na.rm = T)
),
by = .(.id, day_departure)
],
on = c(".id", "day_departure")
]
# plot
ggplot(dataPlot, aes(x = botttime, y = driftrate, col = .id)) + geom_point(size = 0.5,
alpha = 0.5) + geom_smooth(method = "lm") + guides(color = "none") + facet_wrap(.id ~
.) + scale_x_continuous(limits = c(0, 700)) + labs(x = "Daily median Bottom time (s)",
y = "Daily median drift rate (m.s-1)") + theme_jjo()
# plot
ggplot(dataPlot, aes(x = maxdepth, y = driftrate, col = .id)) + geom_point(size = 0.5,
alpha = 0.5) + geom_smooth(method = "lm") + guides(color = "none") + facet_wrap(.id ~
.) + labs(x = "Daily median Maximum depth (m)", y = "Daily median drift rate (m.s-1)") +
theme_jjo()
# plot
ggplot(dataPlot, aes(x = dduration, y = driftrate, col = .id)) + geom_point(size = 0.5,
alpha = 0.5) + geom_smooth(method = "lm") + guides(color = "none") + facet_wrap(.id ~
.) + labs(x = "Daily median Dive duration (s)", y = "Daily median drift rate (m.s-1)") +
theme_jjo()
Behavioral Aerobic Dive Limit (bADL)
# dive duration vs pdi by days
ggplot(data = data_2018_filter[pdi < 300, ], aes(x = dduration, y = pdi, color = .id,
group = dduration, fill = "none")) + geom_boxplot(show.legend = FALSE, outlier.alpha = 0.05,
alpha = 0) + labs(x = "Dive duration (s)", y = "Post-dive duration (s)") + facet_wrap(. ~
.id, scales = "free_x") + theme_jjo()
# dive duration vs pdi by days
ggplot(data = data_2018_filter[pdi < 300, ], aes(x = dduration, y = pdi, color = .id)) +
geom_point(show.legend = FALSE, alpha = 0.05) + geom_smooth(method = "gam", show.legend = FALSE,
col = "black", linetype = "dashed") + labs(x = "Dive duration (s)", y = "Post-dive duration (s)") +
facet_wrap(. ~ .id, scales = "free_x") + theme_jjo()
# dive duration vs pdi by days
ggplot(data = data_2018_filter[pdi < 300, .(.id, pdi_ratio = pdi/dduration, day_departure)],
aes(x = day_departure, y = pdi_ratio, color = .id, group = day_departure, fill = "none")) +
geom_boxplot(show.legend = FALSE, outlier.alpha = 0.05, alpha = 0) + labs(x = "# days since departure",
y = "Post-dive / Dive duration ratio") + facet_wrap(. ~ .id, scales = "free_x") +
# zoom
coord_cartesian(ylim = c(0, 0.4)) + theme_jjo()
Based on Shero et al. (2018), we decided to look at the bADL as the 95th percentile of dive duration each day, for those with \(n \geq 50\). This threshold was chosen following this figure:
ggplot(data_2018_filter[, .(nb_dives = .N), by = .(.id, day_departure)], aes(x = nb_dives,
fill = .id)) + geom_histogram(show.legend = FALSE) + facet_grid(. ~ .id) + labs(y = "# of days",
x = "# of dives per day") + theme_jjo()
# select day that have at least 50 dives
days_to_keep = data_2018_filter[,
.(nb_dives = .N),
by = .(.id, day_departure)] %>%
.[nb_dives >= 50,]
# keep only those days
data_2018_filter_complete_day = merge(data_2018_filter,
days_to_keep,
by = c(".id", "day_departure"))
# data plot
dataPlot = data_2018_filter_complete_day[,
.(badl = quantile(dduration, 0.95)),
by = .(.id, day_departure)]
# combine two datasets to be able to use a second axis
# https://stackoverflow.com/questions/49185583/two-y-axes-with-different-scales-for-two-datasets-in-ggplot2
dataMegaPlot = rbind(data_2018_filter_complete_day[divetype == "2: drift"] %>%
.[, .(w = .id,
y = driftrate,
x = day_departure,
z = "second_plot")],
dataPlot[, .(
w = .id,
# tricky one
y = (badl / 1000) - 1,
x = day_departure,
z = "first_plot"
)])
# plot
ggplot() +
geom_point(
data = dataMegaPlot[z == "second_plot", ],
aes(x = x, y = y),
alpha = 1 / 10,
size = 0.5,
color = "grey40",
show.legend = FALSE
) +
geom_path(data = dataMegaPlot[z == "first_plot", ],
aes(x = x, y = y, color = w),
show.legend = FALSE) +
scale_y_continuous(
# Features of the first axis
name = "Drift rate (m/s)",
# Add a second axis and specify its features
sec.axis = sec_axis( ~ (. * 1000) + 1000, name = "Behavioral Aerobic Dive Limit (s)")
) +
labs(x = "# days since departure") +
facet_wrap(w ~ .) +
theme_jjo()
Looking at this graph, I want to believe that there is some kind of relationship between the bADL as defined by Shero et al. (2018) and the drift rate (and so buyoancy).
# get badl
dataplot_1 = data_2018_filter_complete_day[, .(badl = quantile(dduration, 0.95)),
by = .(.id, day_departure)]
# get driftrate
dataplot_2 = data_2018_filter_complete_day[divetype == "2: drift", .(driftrate = median(driftrate)),
by = .(.id, day_departure)]
# merge
dataPlot = merge(dataplot_1, dataplot_2, by = c(".id", "day_departure"), all = TRUE)
# plot
ggplot(data = dataPlot, aes(x = badl, y = driftrate, col = .id)) + geom_point(show.legend = FALSE) +
facet_wrap(.id ~ ., scales = "free") + theme_jjo()

ind_2018070
# ind_2018070
plot_ly(x = dataPlot[.id == "ind_2018070", badl], y = dataPlot[.id == "ind_2018070",
day_departure], z = dataPlot[.id == "ind_2018070", driftrate], type = "scatter3d",
mode = "markers", marker = list(size = 2), color = dataPlot[.id == "ind_2018070",
day_departure]) %>%
layout(scene = list(xaxis = list(title = "Behavioral ADL"), yaxis = list(title = "# days since departure"),
zaxis = list(title = "Drift rate (m/s)")))
ind_2018072
# ind_2018072
plot_ly(x = dataPlot[.id == "ind_2018072", badl], y = dataPlot[.id == "ind_2018072",
day_departure], z = dataPlot[.id == "ind_2018072", driftrate], type = "scatter3d",
mode = "markers", marker = list(size = 2), color = dataPlot[.id == "ind_2018072",
day_departure]) %>%
layout(scene = list(xaxis = list(title = "Behavioral ADL"), yaxis = list(title = "# days since departure"),
zaxis = list(title = "Drift rate (m/s)")))
ind_2018074
# ind_2018074
plot_ly(x = dataPlot[.id == "ind_2018074", badl], y = dataPlot[.id == "ind_2018074",
day_departure], z = dataPlot[.id == "ind_2018074", driftrate], type = "scatter3d",
mode = "markers", marker = list(size = 2), color = dataPlot[.id == "ind_2018074",
day_departure]) %>%
layout(scene = list(xaxis = list(title = "Behavioral ADL"), yaxis = list(title = "# days since departure"),
zaxis = list(title = "Drift rate (m/s)")))
ind_2018072
# ind_2018080
plot_ly(x = dataPlot[.id == "ind_2018080", badl], y = dataPlot[.id == "ind_2018080",
day_departure], z = dataPlot[.id == "ind_2018080", driftrate], type = "scatter3d",
mode = "markers", marker = list(size = 2), color = dataPlot[.id == "ind_2018080",
day_departure]) %>%
layout(scene = list(xaxis = list(title = "Behavioral ADL"), yaxis = list(title = "# days since departure"),
zaxis = list(title = "Drift rate (m/s)")))
GPS data
# This piece of code is only there to show how to draw a polylines with a
# gradient color using leaflet. We're not using it due to the size of the
# created map, and will continue using circle marker
# datasets used to display map
df_driftrate = unique(data_2018_filter[.id == "ind_2018070" & divetype == "2: drift",
.(.id, lat, lon, dduration)])
# color palette
pal <- colorNumeric(palette = "YlGnBu", domain = df_driftrate$dduration)
# add
df_driftrate[, `:=`(nextLat = shift(lat), nextLon = shift(lon), color = pal(df_driftrate$dduration))]
# interactive map
gradient_map <- leaflet() %>%
setView(lng = -122, lat = 38, zoom = 2) %>%
addTiles()
# add lines
for (i in 1:nrow(df_driftrate)) {
gradient_map <- addPolylines(map = gradient_map, data = df_driftrate, lat = as.numeric(df_driftrate[i,
c("lat", "nextLat")]), lng = as.numeric(df_driftrate[i, c("lon", "nextLon")]),
color = df_driftrate[i, color], weight = 3, group = "individual_1")
}
# add layer control
gradient_map <- addLayersControl(map = gradient_map, overlayGroups = c("individual_1"),
options = layersControlOptions(collapsed = FALSE))
# format(object.size(gradient_map), units = 'Mb')
Because for some data the contrast in changes was not enough marked, the only treatment applied on these data is to remove outliers for each variable using the interquartile range rule.
# interactive map
gradient_map <- leaflet() %>%
setView(lng = -132, lat = 48, zoom = 4) %>%
addTiles()
# loop by individuals and variable
grps = NULL
for (i in seq(data_2018_filter[!is.na(lat), unique(.id)])) {
for (k in c("dduration", "maxdepth", "efficiency", "driftrate")) {
if (k == "driftrate") {
# set dataset used to plot
dataPlot = unique(data_2018_filter %>%
.[order(date), ] %>%
.[.id == data_2018_filter[!is.na(lat), unique(.id)][i] & divetype ==
"2: drift" & !is.na(get(k)), c("lat", "lon", k), with = FALSE] %>%
.[!is_outlier(get(k)), ])
# color palette creation
colPal <- colorNumeric(palette = "BrBG", domain = seq(-dataPlot[, max(abs(driftrate))],
dataPlot[, max(abs(driftrate))], 0.1))
} else {
# set dataset used to plot
dataPlot = unique(data_2018_filter %>%
.[order(date), ] %>%
.[.id == data_2018_filter[!is.na(lat), unique(.id)][i] & divetype !=
"2: drift" & !is.na(get(k)), c("lat", "lon", k), with = FALSE] %>%
.[!is_outlier(get(k)), ])
# color palette creation
colPal <- colorNumeric(palette = "YlGnBu", domain = dataPlot[, get(k)])
}
# add color to dataset
dataPlot[, `:=`(color, colPal(dataPlot[, get(k)]))]
# add size column
dataPlot[, `:=`(radius, 3)]
# mark the beginning of the trip
dataPlot[1, `:=`(color = "green", radius = 4)]
# mark the end of the trip
dataPlot[.N, `:=`(color = "red", radius = 4)]
# reorder to make the end and the beginning in front
dataPlot = rbind(dataPlot[-1, ], dataPlot[1, ])
# add markers to map
gradient_map <- addCircleMarkers(map = gradient_map, data = dataPlot, lat = ~lat,
lng = ~lon, radius = ~radius, stroke = FALSE, color = ~color, fillOpacity = 1,
group = paste(data_2018_filter[, unique(.id)][i], "-", k)) %>%
addLegend("bottomleft", data = dataPlot, group = paste(data_2018_filter[,
unique(.id)][i], "-", k), pal = colPal, values = ~get(k), title = k,
opacity = 1)
# retrieve groups
grps = c(grps, paste(data_2018_filter[, unique(.id)][i], "-", k))
}
}
# add layer control
gradient_map <- addLayersControl(map = gradient_map, overlayGroups = grps, options = layersControlOptions(collapsed = TRUE)) %>%
hideGroup(grps)
# display
gradient_map
LS0tCnRpdGxlOiAiRGF0YSBFeHBsb3JhdGlvbiIKYXV0aG9yOiAiSm9mZnJleSBKT1VNQUEiCmRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgZm9ybWF0ID0gJyVkICVCICVZJylgIgpvdXRwdXQ6CiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOgogICAgY3NzOiBjb3Ntb19jdXN0b20uY3NzCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBkZl9wcmludDogZGVmYXVsdAogICAgZmlnX2NhcHRpb246IHllcwogICAgY29kZV9kb3dubG9hZDogeWVzCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHllcwogICAgICBzbW9vdGhfc2Nyb2xsOiBubwp2aWduZXR0ZTogPgogICVcVmlnbmV0dGVJbmRleEVudHJ5e0RhdGEgRXhwbG9yYXRpb259CiAgJVxWaWduZXR0ZUVuZ2luZXtrbml0cjo6cm1hcmtkb3dufQogICVcVmlnbmV0dGVFbmNvZGluZ3tVVEYtOH0KLS0tCiAgCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQojIGNvbW1hbmQgdG8gYnVpbGQgcGFja2FnZSB3aXRob3V0IGdldHRpbmcgdmlnbmV0dGUgZXJyb3IKIyBodHRwczovL2dpdGh1Yi5jb20vcnN0dWRpby9yZW52L2lzc3Vlcy84MzMKIyBkZXZ0b29sczo6Y2hlY2soYnVpbGRfYXJncz1jKCItLW5vLWJ1aWxkLXZpZ25ldHRlcyIpKQoKIyByZWR1Y2UgcG5nIHNpemUKa25pdHI6OmtuaXRfaG9va3Mkc2V0KG9wdGlwbmcgPSBrbml0cjo6aG9va19vcHRpcG5nKQprbml0cjo6a25pdF9ob29rcyRzZXQocG5ncXVhbnQgPSBrbml0cjo6aG9va19wbmdxdWFudCkKCiMgZ2xvYmFsIG9wdGlvbiByZWxhdGl2ZSB0byBybWFya2Rvd24Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBUUlVFLAogIGZpZy5hbGlnbiA9ICJjZW50ZXIiLAogIG91dC53aWR0aCA9ICIxMDAlIiwKICBtZXNzYWdlID0gRkFMU0UsCiAgd2FybmluZyA9IEZBTFNFLAogIHRpZHkgPSBUUlVFLAogIG9wdGlwbmcgPSAiLW83IC1xdWlldCIsCiAgcG5ncXVhbnQgPSAiLS1zcGVlZD0xIgopCgojIGxpYnJhcnkKbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoa2FibGVFeHRyYSkKbGlicmFyeShsZWFmbGV0KQpsaWJyYXJ5KGd0c3VtbWFyeSkgIyBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvZ3RzdW1tYXJ5L3ZpZ25ldHRlcy90Ymxfc3VtbWFyeS5odG1sCmxpYnJhcnkoY29ycnBsb3QpCmxpYnJhcnkoZ2djb3JycGxvdCkKbGlicmFyeShnZ25ld3NjYWxlKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KERUKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShnZW9zcGhlcmUpCgojIHJlbW92ZSBzb21lIHdhcm5pbmdzCnN1cHByZXNzV2FybmluZ3MobGlicmFyeShnZ3Bsb3QyKSkKCiMgZGVmaW5lIG15IG93biB0YWJsZSBmb3JtYXQ6IGh0dHBzOi8vZ2l0aHViLmNvbS9oYW96aHUyMzMva2FibGVFeHRyYS9pc3N1ZXMvMzc0CnNhYmxlIDwtIGZ1bmN0aW9uKHgsIGVzY2FwZSA9IFQsIC4uLikgewogIGtuaXRyOjprYWJsZSh4LCBlc2NhcGUgPSBlc2NhcGUsIC4uLikgJT4lCiAgICBrYWJsZV9zdHlsaW5nKAogICAgICBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAicmVzcG9uc2l2ZSIpLAogICAgICBmdWxsX3dpZHRoID0gRgogICAgKQp9CgojIHRoZW1lIGdncGxvdAojIGJhc2VkOiBodHRwczovL2JlbmphbWlubG91aXMtc3RhdC5mci9lbi9ibG9nLzIwMjAtMDUtMjEtYXN0dWNlcy1nZ3Bsb3Qtcm1hcmtkb3duLwp0aGVtZV9qam8gPC0gZnVuY3Rpb24oYmFzZV9zaXplID0gMTIpIHsKICB0aGVtZV9idyhiYXNlX3NpemUgPSBiYXNlX3NpemUpICUrcmVwbGFjZSUKICAgIHRoZW1lKAogICAgICAjIHRoZSB3aG9sZSBmaWd1cmUKICAgICAgIyBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMSksIGZhY2UgPSAiYm9sZCIsIG1hcmdpbiA9IG1hcmdpbigwLDAsNSwwKSwgaGp1c3QgPSAwKSwKICAgICAgIyBmaWd1cmUgYXJlYQogICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICMgYXhlcwogICAgICAjIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgwLjg1KSwgZmFjZSA9ICJib2xkIiksCiAgICAgICMgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC43MCksIGZhY2UgPSAiYm9sZCIpLAogICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiYmxhY2siLCBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4yLCAibGluZXMiKSwgdHlwZSA9ICJjbG9zZWQiKSksCiAgICAgICMgbGVnZW5kCiAgICAgICMgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC44NSksIGZhY2UgPSAiYm9sZCIpLAogICAgICAjIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC43MCksIGZhY2UgPSAiYm9sZCIpLAogICAgICAjIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSwKICAgICAgIyBsZWdlbmQua2V5LnNpemUgPSB1bml0KDEuNSwgImxpbmVzIiksCiAgICAgICMgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSwKICAgICAgIyBMZXMgPFUrMDBFOT50aXF1ZXR0ZXMgZGFucyBsZSBjYXMgZCd1biBmYWNldHRpbmcKICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiM4ODg4ODgiLCBjb2xvciA9ICIjODg4ODg4IiksCiAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgwLjg1KSwgZmFjZSA9ICJib2xkIiwgY29sb3IgPSAid2hpdGUiLCBtYXJnaW4gPSBtYXJnaW4oNSwgMCwgNSwgMCkpCiAgICApCn0KYGBgCgojIyB7LnVubnVtYmVyZWR9CgpUaGlzIGRvY3VtZW50IGFpbXMgYXQgZXhwbG9yaW5nIHR3byBkYXRhc2V0cywgb25lIGluIDIwMTYgb24gNiBpbmRpdmlkdWFscyBhbmQgYW5vdGhlciBvbmUgaW4gMjAxOCBvbiA0IGluZGl2aWR1YWxzLiBGb3IgdGhhdCBwdXJwb3NlLCB3ZSBuZWVkIGZpcnN0IHRvIGxvYWQgdGhlIGB3ZWFubGluZ05FU2AgcGFja2FnZSB0byBsb2FkIGRhdGEuCgpgYGB7cn0KIyBsb2FkIGxpYnJhcnkKbGlicmFyeSh3ZWFubGluZ05FUykKCiMgbG9hZCBkYXRhCmRhdGEoImRhdGFfbmVzIiwgcGFja2FnZSA9ICJ3ZWFubGluZ05FUyIpCiMgbG9hZCgiLi4vZGF0YS9kYXRhX25lcy5yZGEiKQpgYGAKCiMjIDIwMTYtaW5kaXZpZHVhbHMgCgpMZXQncyBoYXZlIGEgbG9vayBhdCB3aGF0J3MgaW5zaWRlIGBkYXRhX25lcyRkYXRhXzIwMTZgOgogIApgYGB7cn0KIyBsaXN0IHN0cnVjdHVyZQpzdHIoZGF0YV9uZXMkeWVhcl8yMDE2LCBtYXgubGV2ZWwgPSAxLCBnaXZlLmF0dHIgPSBGLCBuby5saXN0ID0gVCkKYGBgCgo+IEEgbGlzdCBvZiBgciBsZW5ndGgoZGF0YV9uZXMkeWVhcl8yMDE2KWAgYGRhdGEuZnJhbWVzYCwgb25lIGZvciBlYWNoIHNlYWwKCkZvciBjb252ZW5pZW5jZSwgd2UgYWdncmVnYXRlIGFsbCBgciBsZW5ndGgoZGF0YV9uZXMkeWVhcl8yMDE2KWAgaW5kaXZpZHVhbHMgaW50byBvbmUgZGF0YXNldC4KCmBgYHtyLCBldmFsPUZBTFNFfQojIGNvbWJpbmUgYWxsIGluZGl2aWR1YWxzCmRhdGFfMjAxNiA8LSByYmluZGxpc3QoZGF0YV9uZXMkeWVhcl8yMDE2LCB1c2UubmFtZSA9IFRSVUUsIGlkY29sID0gVFJVRSkKCiMgZGlzcGxheQpEVDo6ZGF0YXRhYmxlKGRhdGFfMjAxNltzYW1wbGUuaW50KC5OLCAxMDApLCBdLCBvcHRpb25zID0gbGlzdChzY3JvbGxYID0gVCkpCmBgYApgYGB7ciwgZWNobz1GQUxTRSwgcmVzdWx0cz0nYXNpcyd9CiMgY29tYmluZSBhbGwgaW5kaXZpZHVhbHMKZGF0YV8yMDE2IDwtIHJiaW5kbGlzdChkYXRhX25lcyR5ZWFyXzIwMTYsIHVzZS5uYW1lID0gVFJVRSwgaWRjb2wgPSBUUlVFKQoKIyB0aXRsZQpjYXQoIjx0YWJsZSBzdHlsZT0nd2lkdGg6IDUwJSc+IiwgcGFzdGUwKCI8Y2FwdGlvbj4iLCAiKCN0YWI6bXlEVGh0bWx0b29scykiLCAiU2FtcGxlIG9mIDEwMCByYW5kb20gcm93cyBmcm9tIGBkYXRhXzIwMTZgIiwgIjwvY2FwdGlvbj4iKSwgIjwvdGFibGU+Iiwgc2VwID0gIlxuIikKCiMgZGlzcGxheQpEVDo6ZGF0YXRhYmxlKGRhdGFfMjAxNltzYW1wbGUuaW50KC5OLCAxMDApLCBdLCBvcHRpb25zID0gbGlzdChzY3JvbGxYID0gVCkpCmBgYAoKIyMjIFN1bW1hcnkKCmBgYHtyfQojIHJhd19kYXRhCmRhdGFfMjAxNlssIC4oCiAgbmJfZGF5c19yZWNvcmRlZCA9IHVuaXF1ZU4oYXMuRGF0ZShkYXRlKSksCiAgbWF4X2RlcHRoID0gbWF4KG1heHByZXNzX2RiYXJzKSwKICBzc3RfbWVhbiA9IG1lYW4oc3N0Ml9jKSwKICBzc3Rfc2QgPSBzZChzc3QyX2MpCiksIGJ5ID0gLmlkXSAlPiUKICBzYWJsZSgKICAgIGNhcHRpb24gPSAiU3VtbWFyeSBkaXZpbmcgaW5mb3JtYXRpb24gcmVsYXRpdmUgdG8gZWFjaCAyMDE2IGluZGl2aWR1YWwiLAogICAgZGlnaXRzID0gMgogICkKYGBgCgpXZWxsLCBpdCBzZWVtcyB0aGF0IGBzc3RgIGlzIGEgYml0IG9kZC4gTGV0J3MgaGF2ZSBhIGxvb2sgYXQgaXRzIGRpc3RyaWJ1dGlvbi4KCmBgYHtyLCBmaWcuY2FwPSJEaXN0cmlidXRpb24gb2YgcmF3IGBzc3QyYCBmb3IgdGhlIGZvdXIgaW5kaXZpZHVhbHMgaW4gMjAxNiJ9CmdncGxvdChkYXRhXzIwMTYsIGFlcyh4ID0gc3N0Ml9jLCBmaWxsID0gLmlkKSkgKwogIGdlb21faGlzdG9ncmFtKHNob3cubGVnZW5kID0gRkFMU0UpICsKICBmYWNldF93cmFwKC5pZCB+IC4pICsKICB0aGVtZV9qam8oKQpgYGAKCkxldCdzIHJlbW92ZSBhbnkgZGF0YSB3aXRoIGEgYHNzdDJfY2AgPiA1MDAuCgpgYGB7ciwgZmlnLmNhcD0iRGlzdHJpYnV0aW9uIG9mIGZpbHRlcmVkIGBzc3QyYCBmb3IgdGhlIGZvdXIgaW5kaXZpZHVhbHMgaW4gMjAxNiJ9CmRhdGFfMjAxNl9maWx0ZXIgPC0gZGF0YV8yMDE2W3NzdDJfYyA8IDUwMCwgXQpnZ3Bsb3QoZGF0YV8yMDE2X2ZpbHRlciwgYWVzKHggPSBzc3QyX2MsIGZpbGwgPSAuaWQpKSArCiAgZ2VvbV9oaXN0b2dyYW0oc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGZhY2V0X3dyYXAoLmlkIH4gLikgKwogIHRoZW1lX2pqbygpCmBgYAoKV2VsbCwgdGhhdCBzZWVtcyB0byBiZSBtdWNoIGJldHRlciEgSW4gdGhlIHByb2Nlc3Mgb2YgZmlsdGVyaW5nIG91dCBvZGQgdmFsdWVzLCB3ZSByZW1vdmVkIGByIGRhdGFfMjAxNlssLk5dIC0gZGF0YV8yMDE2X2ZpbHRlclssLk5dYCByb3dzIHRoaXMgd2F5OgoKYGBge3J9CiMgbmJyb3cgcmVtb3ZlZApkYXRhXzIwMTZbc3N0Ml9jID4gNTAwLCAuKG5iX3Jvd19yZW1vdmVkID0gLk4pLCBieSA9IC5pZF0gJT4lCiAgc2FibGUoY2FwdGlvbiA9ICIjIG9mIHJvd3MgcmVtb3ZlZCBieSAyMDE2LWluZGl2aWR1YWxzIikKYGBgCmBgYHtyLCBmaWcuY2FwPSJXaGVyZSBhbmQgd2hlbiB0aGUgYHNzdDJgIG91dGxpZXJzIG9jY3VyZWQiLCBmaWcud2lkdGg9OX0KIyBtYXggZGVwdGgKZ2dwbG90KAogIGRhdGFfMjAxNiwKICBhZXMoeSA9IC1tYXhwcmVzc19kYmFycywgeCA9IGFzLkRhdGUoZGF0ZSksIGNvbCA9IC5pZCkKKSArCiAgZ2VvbV9wYXRoKHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkYXRhXzIwMTZbc3N0Ml9jID4gNTAwLCBdLCBjb2wgPSAiYmxhY2siKSArCiAgc2NhbGVfeF9kYXRlKGRhdGVfbGFiZWxzID0gIiVtLyVZIikgKwogIGxhYnMoeSA9ICJQcmVzc3VyZSAoZGJhcikiLCB4ID0gIkRhdGUiKSArCiAgZmFjZXRfd3JhcCguaWQgfiAuKSArCiAgdGhlbWVfampvKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCmBgYApXZWxsIHRoaXMgbGF0dGVyIHBsb3QgaGlnaGxpZ2h0cyBzZXZlcmFsIHBvaW50czoKCiogbW9zdCBvZiB0aGUgb3V0bGllcnMgb2NjdXIgd2hpbGUgYW5pbWFscyBzcGVuZCB0aGUgd2hvbGUgZGF5IGF0IHRoZSBzdXJmYWNlIChvciBvbiB0aGUgZ3JvdW5kKSwgcHJvYmFibHkgcmVzdGluZywgc28gZXNzZW50aWFsbHkgYXQgdGhlIGJlZ2lubmluZyBhbmQgdGhlIGVuZCBvZiBlYWNoIHRyYWNrCiogd2UgY2FuIGFscmVhZHkgc2VlIHRoYXQgYGluZF8zNDQ5YCBzZWVtcyB0byBoYXZlIHJldHVybiBhc2hvcmUgdHdpY2UgZHVyaW5nIGhpcyB0cmFjawoKTGV0J3Mgc2VlIGlmIHdlIGNhbiBkb3VibGUgY2hlY2sgdGhhdCwgdXNpbmcgYSBtYXAuCgpgYGB7ciwgZmlnLmNhcD0iSXQgaXMgc3VwcG9zZWQgdG8gYmUgdGhlIHRyYWNrIG9mIGBpbmRfMzQ0OWAuLi4gKHJlZCBkb3RzIGFyZSB0aGUgbG9jYXRpb24gb2YgcmVtb3ZlZCByb3dzKSIsIGZpZy53aWR0aD04fQojIGludGVyYWN0aXZlIG1hcApsZWFmbGV0KCkgJT4lCiAgc2V0VmlldyhsbmcgPSAtMTIyLCBsYXQgPSAzOCwgem9vbSA9IDIpICU+JQogIGFkZFRpbGVzKCkgJT4lCiAgYWRkUG9seWxpbmVzKAogICAgbGF0ID0gZGF0YV8yMDE2Wy5pZCA9PSAiaW5kXzM0NDkiLCBsYXRpdHVkZV9kZWdzXSwKICAgIGxuZyA9IGRhdGFfMjAxNlsuaWQgPT0gImluZF8zNDQ5IiwgbG9uZ2l0dWRlX2RlZ3NdLAogICAgd2VpZ2h0ID0gMgogICkgJT4lCiAgYWRkQ2lyY2xlTWFya2VycygKICAgIGxhdCA9IGRhdGFfMjAxNlsuaWQgPT0gImluZF8zNDQ5IiAmIHNzdDJfYyA+IDUwMCwgbGF0aXR1ZGVfZGVnc10sCiAgICBsbmcgPSBkYXRhXzIwMTZbLmlkID09ICJpbmRfMzQ0OSIgJiBzc3QyX2MgPiA1MDAsIGxvbmdpdHVkZV9kZWdzXSwKICAgIHJhZGl1cyA9IDMsCiAgICBzdHJva2UgPSBGQUxTRSwKICAgIGNvbG9yID0gInJlZCIsCiAgICBmaWxsT3BhY2l0eSA9IDEKICApCmBgYAoKLi4uIHRoZXNlIGNvb3JkaW5hdGVzIHNlZW0gd2VpcmQgIQoKYGBge3J9CiMgc3VtbWFyeSBvZiB0aGUgY29vcmRpbmF0ZXMgYnkgaW5kaXZpZHVhbHMKZGF0YV8yMDE2WywgLiguaWQsIGxvbmdpdHVkZV9kZWdzLCBsYXRpdHVkZV9kZWdzKV0gJT4lCiAgdGJsX3N1bW1hcnkoYnkgPSAuaWQpICU+JQogIG1vZGlmeV9jYXB0aW9uKCJTdW1tYXJ5IG9mIGBsb25naXR1ZGVfZGVncmVlYCBhbmQgYGxhdGl0dWRlX2RlZ3JlZWAiKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9OSwgZmlnLmNhcD0iRGlzdHJpYnV0aW9uIG9mIGNvb3JkaW5hdGVzIHBlciBzZWFsIn0KIyBkaXN0cmlidXRpb24gY29vcmRpbmF0ZXMKZ2dwbG90KAogIGRhdGEgPSBtZWx0KGRhdGFfMjAxNlssIC4oCiAgICBMb25naXR1ZGUgPSBsb25naXR1ZGVfZGVncywKICAgIExhdGl0dWRlID0gbGF0aXR1ZGVfZGVncywKICAgIC5pZAogICldLAogIGlkLnZhcnMgPQogICAgIi5pZCIsIHZhbHVlLm5hbWUgPSAiQ29vcmRpbmF0ZSIKICApLAogIGFlcyh4ID0gQ29vcmRpbmF0ZSwgZmlsbCA9IC5pZCkKKSArCiAgZ2VvbV9oaXN0b2dyYW0oc2hvdy5sZWdlbmQgPSBGKSArCiAgZmFjZXRfZ3JpZCh2YXJpYWJsZSB+IC5pZCkgKwogIHRoZW1lX2pqbygpCmBgYAoKVGhlcmUgaXMgZGVmaW5pdGVseSBzb21ldGhpbmcgd3Jvbmcgd2l0aCB0aGVzZSBjb29yZGluYXRlcyAoZml2ZSBzZWFscyB3b3VsZCBoYXZlIGNyb3NzZWQgdGhlIGVxdWF0b3IuLi4pLCBidXQgdGhlIHJlcHJlc2VudGF0aW9uIG9mIHRoZSB0cmFjayBjYW4gYWxzbyBiZSBpbXByb3ZlZCEgSGVyZSBhcmUgdGhlIHNvbWUgcG9pbnRzIHRvIGV4cGxvcmU6CgoqIEZvciBgbG9uZ2l0dWRlYCBhIHBhcnQgb2YgdGhlIGRhdGEgc2VlbXMgdG8gaGF2ZSBhIHdyb25nIHNpZ24sIHJlc3VsdGluZyBpbiB0aGVzZSBkaXN0cmlidXRpb24sIHRoYXQgYXBwZWFyIHRvIGJlIGN1dCBvZmYKKiBGb3IgYGxhdGl0dWRlYCwgd2VsbCB0aGlzIGlzIGVuc3VyZSBidXQgbWF5YmUgdGhlIHNhbWUgcHJvYmxlbSBvY2N1cnMKCkxldCdzIHRyeSB0byBwbGF5IG9uIGNvb3JkaW5hdGVzJyBzaWduIHRvIHNlZSBpZiB3ZSBjYW4gZGlzcGxheSBzb21ldGhpbmcgdGhhdCBtYWtlcyBtb3JlIHNlbnNlLgoKYGBge3IsIGZpZy5jYXA9IkFuIGF0dGVtcHQgdG8gZGlzcGxheSB0aGUgYGluZF8zNDQ5YCdzIHRyYWNrIiwgZmlnLndpZHRoPTh9CiMgaW50ZXJhY3RpdmUgbWFwCmxlYWZsZXQoKSAlPiUKICBzZXRWaWV3KGxuZyA9IC0xMjIsIGxhdCA9IDUwLCB6b29tID0gMykgJT4lCiAgYWRkVGlsZXMoKSAlPiUKICBhZGRQb2x5bGluZXMoCiAgICBsYXQgPSBkYXRhXzIwMTZbLmlkID09ICJpbmRfMzQ0OSIsIGFicyhsYXRpdHVkZV9kZWdzKV0sCiAgICBsbmcgPSBkYXRhXzIwMTZbLmlkID09ICJpbmRfMzQ0OSIsIC1hYnMobG9uZ2l0dWRlX2RlZ3MpXSwKICAgIHdlaWdodCA9IDIKICApCmBgYAoKPiBJJ2xsIGJldHRlciBhc2sgUm94YW5uZSEKICAKIyMjIE1pc3NpbmcgdmFsdWVzCiAgCmBgYHtyIGZpZy5jYXA9IkNoZWNrIGZvciBtaXNzaW5nIHZhbHVlIGluIDIwMTYtaW5kaXZpZHVhbHMiLCBvdXQud2lkdGg9IjEwMCUifQojIGJ1aWxkIGRhdGFzZXQgdG8gY2hlY2sgZm9yIG1pc3NpbmcgdmFsdWVzCmRhdGFQbG90IDwtIG1lbHQoZGF0YV8yMDE2X2ZpbHRlclssIC4oLmlkLCBpcy5uYSguU0QpKSwgLlNEY29sID0gLWMoCiAgIi5pZCIsCiAgInJlYyMiLAogICJkYXRlIiwKICAidGltZSIKKV0pCiMgYWRkIHRoZSBpZCBvZiByb3dzCmRhdGFQbG90WywgaWRfcm93IDo9IGMoMTouTiksIGJ5ID0gYygidmFyaWFibGUiLCAiLmlkIildCgojIHBsb3QKZ2dwbG90KGRhdGFQbG90LCBhZXMoeCA9IHZhcmlhYmxlLCB5ID0gaWRfcm93LCBmaWxsID0gdmFsdWUpKSArCiAgZ2VvbV90aWxlKCkgKwogIGxhYnMoeCA9ICJBdHRyaWJ1dGVzIiwgeSA9ICJSb3dzIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKAogICAgdmFsdWVzID0gYygid2hpdGUiLCAiYmxhY2siKSwKICAgIGxhYmVscyA9IGMoIlJlYWwiLCAiTWlzc2luZyIpCiAgKSArCiAgZmFjZXRfd3JhcCguaWQgfiAuLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIHRoZW1lX2pqbygpICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIikKICApCmBgYAoKIyMgMjAxOC1pbmRpdmlkdWFscwoKTGV04oCZcyBoYXZlIGEgbG9vayBhdCB3aGF04oCZcyBpbnNpZGUgYGRhdGFfbmVzJGRhdGFfMjAxOGA6CiAgCmBgYHtyfQojIGxpc3Qgc3RydWN0dXJlCnN0cihkYXRhX25lcyR5ZWFyXzIwMTgsIG1heC5sZXZlbCA9IDEsIGdpdmUuYXR0ciA9IEYsIG5vLmxpc3QgPSBUKQpgYGAKCj4gQSBsaXN0IG9mIGByIGxlbmd0aChkYXRhX25lcyR5ZWFyXzIwMTgpYCBgZGF0YS5mcmFtZXNgLCBvbmUgZm9yIGVhY2ggc2VhbAoKRm9yIGNvbnZlbmllbmNlLCB3ZSBhZ2dyZWdhdGUgYWxsIGByIGxlbmd0aChkYXRhX25lcyR5ZWFyXzIwMTgpYCBpbmRpdmlkdWFscyBpbnRvIG9uZSBkYXRhc2V0LgoKYGBge3IsIGV2YWw9RkFMU0V9CiMgY29tYmluZSBhbGwgaW5kaXZpZHVhbHMKZGF0YV8yMDE4IDwtIHJiaW5kbGlzdChkYXRhX25lcyR5ZWFyXzIwMTgpCgojIGRpc3BsYXkKRFQ6OmRhdGF0YWJsZShkYXRhXzIwMThbc2FtcGxlLmludCguTiwgMTAwKSwgXSwgb3B0aW9ucyA9IGxpc3Qoc2Nyb2xsWCA9IFQpKQpgYGAKYGBge3IsIGVjaG89RkFMU0UsIHJlc3VsdHM9J2FzaXMnfQojIGNvbWJpbmUgYWxsIGluZGl2aWR1YWxzCmRhdGFfMjAxOCA8LSByYmluZGxpc3QoZGF0YV9uZXMkeWVhcl8yMDE4KQoKIyB0aXRsZQpjYXQoIjx0YWJsZSBzdHlsZT0nd2lkdGg6IDUwJSc+IiwgcGFzdGUwKCI8Y2FwdGlvbj4iLCAiKCN0YWI6bXlEVGh0bWx0b29scykiLCAiU2FtcGxlIG9mIDEwMCByYW5kb20gcm93cyBmcm9tIGBkYXRhXzIwMThgIiwgIjwvY2FwdGlvbj4iKSwgIjwvdGFibGU+Iiwgc2VwID0gIlxuIikKCiMgZGlzcGxheQoKRFQ6OmRhdGF0YWJsZShkYXRhXzIwMThbc2FtcGxlLmludCguTiwgMTAwKSwgXSwgb3B0aW9ucyA9IGxpc3Qoc2Nyb2xsWCA9IFQpKQpgYGAKCiMjIyBTdW1tYXJ5CgpgYGB7cn0KIyByYXdfZGF0YQpkYXRhXzIwMThbLCAuKAogIG5iX2RheXNfcmVjb3JkZWQgPSB1bmlxdWVOKGFzLkRhdGUoZGF0ZSkpLAogIG5iX2RpdmVzID0gLk4sCiAgbWF4ZGVwdGhfbWVhbiA9IG1lYW4obWF4ZGVwdGgpLAogIGRkdXJhdGlvbl9tZWFuID0gbWVhbihkZHVyYXRpb24pLAogIGJvdHR0aW1lX21lYW4gPSBtZWFuKGJvdHR0aW1lKSwKICBwZGlfbWVhbiA9IG1lYW4ocGRpLCBuYS5ybSA9IFQpCiksIGJ5ID0gLmlkXSAlPiUKICBzYWJsZSgKICAgIGNhcHRpb24gPSAiU3VtbWFyeSBkaXZpbmcgaW5mb3JtYXRpb24gcmVsYXRpdmUgdG8gZWFjaCAyMDE4IGluZGl2aWR1YWwiLAogICAgZGlnaXRzID0gMgogICkKYGBgCj4gVmVyeSBuaWNlIGRhdGFzZXQgOikKCiMjIyBTb21lIGV4cGxhbmF0b3J5IHBsb3RzCgojIyMjIE1pc3NpbmcgdmFsdWVzCgpgYGB7ciBmaWcuY2FwPSJDaGVjayBmb3IgbWlzc2luZyB2YWx1ZSBpbiAyMDE4LWluZGl2aWR1YWxzIiwgZmlnLndpZHRoPTl9CiMgYnVpbGQgZGF0YXNldCB0byBjaGVjayBmb3IgbWlzc2luZyB2YWx1ZXMKZGF0YVBsb3QgPC0gbWVsdChkYXRhXzIwMThbLCAuKC5pZCwgaXMubmEoLlNEKSksIC5TRGNvbCA9IC1jKAogICIuaWQiLAogICJkaXZlbnVtYmVyIiwKICAieWVhciIsCiAgIm1vbnRoIiwKICAiZGF5IiwKICAiaG91ciIsCiAgIm1pbiIsCiAgInNlYyIsCiAgImp1bGRhdGUiLAogICJkaXZldHlwZSIsCiAgImRhdGUiLAogICJwaGFzZSIsCiAgImxhdCIsCiAgImxvbiIKKV0pCiMgYWRkIHRoZSBpZCBvZiByb3dzCmRhdGFQbG90WywgaWRfcm93IDo9IGMoMTouTiksIGJ5ID0gYygidmFyaWFibGUiLCAiLmlkIildCgojIHBsb3QKZ2dwbG90KGRhdGFQbG90LCBhZXMoeCA9IHZhcmlhYmxlLCB5ID0gaWRfcm93LCBmaWxsID0gdmFsdWUpKSArCiAgZ2VvbV90aWxlKCkgKwogIGxhYnMoeCA9ICJBdHRyaWJ1dGVzIiwgeSA9ICJSb3dzIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKAogICAgdmFsdWVzID0gYygid2hpdGUiLCAiYmxhY2siKSwKICAgIGxhYmVscyA9IGMoIlJlYWwiLCAiTWlzc2luZyIpCiAgKSArCiAgZmFjZXRfd3JhcCguaWQgfiAuLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIHRoZW1lX2pqbygpICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIikKICApCmBgYAoKU28gZmFyIHNvIGdvb2QsIG9ubHkgZmV3IHZhcmlhYmxlcyBzZWVtcyB0byBoYXZlIG1pc3NpbmcgdmFsdWVzOgogIApgYGB7cn0KIyB0YWJsZSB3aXRoIHBlcmNlbnQKdGFibGVfaW50ZXIgPC0gZGF0YV8yMDE4WywgbGFwcGx5KC5TRCwgZnVuY3Rpb24oeCkgewogIHJvdW5kKGxlbmd0aCh4W2lzLm5hKHgpXSkgKiAxMDAgLyBsZW5ndGgoeCksIDEpCn0pLCAuU0Rjb2wgPSAtYygKICAiLmlkIiwKICAiZGl2ZW51bWJlciIsCiAgInllYXIiLAogICJtb250aCIsCiAgImRheSIsCiAgImhvdXIiLAogICJtaW4iLAogICJzZWMiLAogICJqdWxkYXRlIiwKICAiZGl2ZXR5cGUiLAogICJkYXRlIiwKICAicGhhc2UiLAogICJsYXQiLAogICJsb24iCildCgojIGZpbmQgd2hpY2ggYXJlIGRpZmZlcmVudCBmcm9tIDAKY29uZF9pbnRlciA8LSBzYXBwbHkodGFibGVfaW50ZXIsIGZ1bmN0aW9uKHgpIHsKICB4ID09IDAKfSkKCiMgZGlzcGxheSB0aGUgcGVyY2VudGFnZXMgdGhhdCBhcmUgb3ZlciAwCnRhYmxlX2ludGVyWywgd2hpY2goY29uZF9pbnRlcikgOj0gTlVMTF0gJT4lCiAgc2FibGUoY2FwdGlvbiA9ICJQZXJjZW50YWdlIG9mIG1pc3NpbmcgdmFsdWVzIHBlciBjb2x1bW5zIGhhdmluZyBtaXNzaW5nIHZhbHVlcyEiKSAlPiUKICBzY3JvbGxfYm94KHdpZHRoID0gIjEwMCUiKQpgYGAKCiMjIyMgT3V0bGllcnMgey50YWJzZXR9CgpPaywgbGV0J3MgaGF2ZSBhIGxvb2sgYXQgYWxsIHRoZSBkYXRhLiBCdXQgZmlyc3QsIHdlIGhhdmUgdG8gcmVtb3ZlIG91dGxpZXJzLiBTb21lIG9mIHRoZW0gYXJlIHF1aWV0IGVhc3kgdG8gc3BvdCBsb29raW5nIGF0IHRoZSBkaXN0cmlidXRpb24gb2YgZGl2ZSBkdXJhdGlvbjoKCiMjIyMjIEJlZm9yZSB7LX0KCmBgYHtyLCBmaWcuY2FwPSdEaXN0cmlidXRpb24gb2YgYGRkdXJhdGlvbmAgZm9yIGVhY2ggc2VhbC4gVGhlIGRhc2hlZCBsaW5lIGhpZ2hsaWdodCB0aGUgInN1YmplY3RpdmUiIHRocmVzaG9sZCB1c2VkIHRvIHJlbW92ZSBvdXRsaWVycyAoMzAwMCBzZWMpJywgZmlnLmhlaWdodD0zfQpnZ3Bsb3QoCiAgZGF0YV8yMDE4WywgLlNEXVssIHN0YXRlIDo9ICJCZWZvcmUiXSwKICBhZXMoeCA9IGRkdXJhdGlvbiwgZmlsbCA9IC5pZCkKKSArCiAgZ2VvbV9oaXN0b2dyYW0oc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDMwMDAsIGxpbmV0eXBlID0gImxvbmdkYXNoIikgKwogIGZhY2V0X2dyaWQoc3RhdGUgfiAuaWQsCiAgICAgICAgICAgICBzY2FsZXMgPSAiZnJlZSIKICApICsKICBsYWJzKHkgPSAiIyBvZiBkaXZlcyIsIHggPSAiRGl2ZSBkdXJhdGlvbiAocykiKSArCiAgdGhlbWVfampvKCkKYGBgCgojIyMjIyBBZnRlciB7LX0KCmBgYHtyLCBmaWcuY2FwPSdTYW1lIGRpc3RyaWJ1dGlvbiBvZiBgZGR1cmF0aW9uYCBmb3IgZWFjaCBzZWFsIGJ1dCBhZnRlciByZW1vdmluZyBhbnkgYGRkdXJhdGlvbmAgPiAzMDAwIHNlYy4gVGhlIGRhc2hlZCBsaW5lIGhpZ2hsaWdodCB0aGUgInN1YmplY3RpdmUiIHRocmVzaG9sZCB1c2VkIHRvIHJlbW92ZSBvdXRsaWVycycsIGZpZy5oZWlnaHQ9M30KZ2dwbG90KAogIGRhdGFfMjAxOFtkZHVyYXRpb24gPCAzMDAwLCBdW11bLCBzdGF0ZSA6PSAiQWZ0ZXIiXSwKICBhZXMoeCA9IGRkdXJhdGlvbiwgZmlsbCA9IC5pZCkKKSArCiAgZ2VvbV9oaXN0b2dyYW0oc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDMwMDAsIGxpbmV0eXBlID0gImxvbmdkYXNoIikgKwogIGZhY2V0X2dyaWQoc3RhdGUgfiAuaWQsCiAgICAgICAgICAgICBzY2FsZXMgPSAiZnJlZSIKICApICsKICBsYWJzKHggPSAiIyBvZiBkaXZlcyIsIHkgPSAiRGl2ZSBkdXJhdGlvbiAocykiKSArCiAgdGhlbWVfampvKCkKYGBgCgpJdCBzZWVtcyBtdWNoIGJldHRlciwgc28gbGV0J3MgcmVtb3ZlIGFueSByb3dzIHdpdGggYGRkdXJhdGlvbmAgPiAzMDAwIHNlYy4KCmBgYHtyfQojIGZpbHRlciBkYXRhCmRhdGFfMjAxOF9maWx0ZXIgPC0gZGF0YV8yMDE4W2RkdXJhdGlvbiA8IDMwMDAsIF0KCiMgbmJyb3cgcmVtb3ZlZApkYXRhXzIwMThbZGR1cmF0aW9uID49IDMwMDAsIC4obmJfcm93X3JlbW92ZWQgPSAuTiksIGJ5ID0gLmlkXSAlPiUKICBzYWJsZShjYXB0aW9uID0gIiMgb2Ygcm93cyByZW1vdmVkIGJ5IDIwMTgtaW5kaXZpZHVhbHMiKQpgYGAKCiMjIyMgQ2hlY2sgZGF5IGFuZCBuaWdodCB7LnRhYnNldH0KCiMjIyMjIExpZ2h0IGxldmVscwoKYGBge3IsIGZpZy5jYXA9IlZpc3VhbGl6YXRpb24gb2YgbGlnaHQgbGV2ZWwgYXQgdGhlIHN1cmZhY2UgYWxvbmcgMjAxOC1pbmRpdmlkdWFscycgdHJpcCIsIGZpZy5oZWlnaHQ9Nn0KIyBsZXQncyBmaXJzdCBhdmVyYWdlIGBsaWdodGF0c3VyZmAgYnkgaW5kaXZpZHVhbHMsIGRheSBzaW5jZSBkZXBhcnR1cmUgYW5kIGhvdXIKZGF0YVBsb3QgPC0gZGF0YV8yMDE4WywgLihsaWdodGF0c3VyZiA9IG1lZGlhbihsaWdodGF0c3VyZikpLAogICAgICAgICAgICAgICAgICAgICAgYnkgPSAuKC5pZCwgZGF5X2RlcGFydHVyZSwgZGF0ZSA9IGFzLkRhdGUoZGF0ZSksIGhvdXIpCl0KCiMgZGlzcGxheSB0aGUgcmVzdWx0CmdncGxvdChkYXRhUGxvdCwgYWVzKHggPSBkYXlfZGVwYXJ0dXJlLCB5ID0gaG91ciwgZmlsbCA9IGxpZ2h0YXRzdXJmKSkgKwogIGdlb21fdGlsZSgpICsKICBmYWNldF9ncmlkKC5pZCB+IC4pICsKICB0aGVtZV9qam8oKSArCiAgbGFicyh4ID0gIiMgb2YgZGF5cyBzaW5jZSBkZXBhcnR1cmUiLCB5ID0gIkhvdXIiLCBmaWxsID0gIkxpZ2h0IGxldmVsIGF0IHRoZSBzdXJmYWNlIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoImJvdHRvbSIpKQpgYGAKCiMjIyMjIERheSBhbmQgbmlnaHQgZGV0ZWN0aW9uCgpgYGB7ciwgZmlnLmNhcD0iVmlzdWFsaXphdGlvbiBvZiBkZXRlY3RlZCBuaWdodCB0aW1lIGFuZCBkYXkgdGltZSBhbG9uZyAyMDE4LWluZGl2aWR1YWxzJyB0cmlwIiwgZmlnLmhlaWdodD02fQojIGxldCdzIGZpcnN0IGF2ZXJhZ2UgYGxpZ2h0YXRzdXJmYCBieSBpbmRpdmlkdWFscywgZGF5IHNpbmNlIGRlcGFydHVyZSBhbmQgaG91cgpkYXRhUGxvdCA8LSBkYXRhXzIwMThbLCAuKGxpZ2h0YXRzdXJmID0gbWVkaWFuKGxpZ2h0YXRzdXJmKSksCiAgICAgICAgICAgICAgICAgICAgICBieSA9IC4oLmlkLCBkYXlfZGVwYXJ0dXJlLCBkYXRlID0gYXMuRGF0ZShkYXRlKSwgaG91ciwgcGhhc2UpCl0KCiMgZGlzcGxheSB0aGUgcmVzdWx0CmdncGxvdChkYXRhUGxvdCwgYWVzKHggPSBkYXlfZGVwYXJ0dXJlLCB5ID0gaG91ciwgZmlsbCA9IHBoYXNlKSkgKwogIGdlb21fdGlsZSgpICsKICBmYWNldF9ncmlkKC5pZCB+IC4pICsKICB0aGVtZV9qam8oKSArCiAgbGFicyh4ID0gIiMgb2YgZGF5cyBzaW5jZSBkZXBhcnR1cmUiLCB5ID0gIkhvdXIiLCBmaWxsID0gIkRheSB0aW1lIGFuZCBuaWdodCB0aW1lIGFzIGRldGVjdGVkIGJ5IHRoZSBgY2FsX3BoYXNlX2RheWAgZnVuY3Rpb24iKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYygiYm90dG9tIikpCmBgYAoKIyMjIyBBbGwgVmFyaWFibGVzIAoKYGBge3J9Cm5hbWVzX2Rpc3BsYXkgPC0gbmFtZXMoZGF0YV8yMDE4X2ZpbHRlclssIC1jKAogICIuaWQiLAogICJkYXRlIiwKICAiZGl2ZW51bWJlciIsCiAgInllYXIiLAogICJtb250aCIsCiAgImRheSIsCiAgImhvdXIiLAogICJtaW4iLAogICJzZWMiLAogICJqdWxkYXRlIiwKICAiZGl2ZXR5cGUiLAogICJldXBob3RpY2RlcHRoIiwKICAidGhlcm1vY2xpbmVkZXB0aCIsCiAgImRheV9kZXBhcnR1cmUiLAogICJwaGFzZSIsCiAgImxhdCIsCiAgImxvbiIKKV0pCmBgYAoKYGBge3IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0KZm9yIChpIGluIG5hbWVzX2Rpc3BsYXkpIHsKICBjYXQoIiMjIyMjIiwgaSwgInsudW5saXN0ZWQgLnVubnVtYmVyZWR9IFxuIikKICBpZiAoaSA9PSAibWF4ZGVwdGgiKSB7CiAgICBwcmludCgKICAgICAgZ2dwbG90KCkgKwogICAgICAgIGdlb21fcG9pbnQoCiAgICAgICAgICBkYXRhID0gZGF0YV8yMDE4X2ZpbHRlclssIC4oCiAgICAgICAgICAgIC5pZCwKICAgICAgICAgICAgZGF0ZSwKICAgICAgICAgICAgdGhlcm1vY2xpbmVkZXB0aAogICAgICAgICAgKV0sCiAgICAgICAgICBhZXMoCiAgICAgICAgICAgIHggPSBhcy5EYXRlKGRhdGUpLAogICAgICAgICAgICB5ID0gLXRoZXJtb2NsaW5lZGVwdGgsCiAgICAgICAgICAgIGNvbG91ciA9ICJUaGVybW9jbGluZSAobSkiCiAgICAgICAgICApLAogICAgICAgICAgYWxwaGEgPSAuMiwKICAgICAgICAgIHNpemUgPSAuNQogICAgICAgICkgKwogICAgICAgIGdlb21fcG9pbnQoCiAgICAgICAgICBkYXRhID0gZGF0YV8yMDE4X2ZpbHRlclssIC4oCiAgICAgICAgICAgIC5pZCwKICAgICAgICAgICAgZGF0ZSwKICAgICAgICAgICAgZXVwaG90aWNkZXB0aAogICAgICAgICAgKV0sCiAgICAgICAgICBhZXMoCiAgICAgICAgICAgIHggPSBhcy5EYXRlKGRhdGUpLAogICAgICAgICAgICB5ID0gLWV1cGhvdGljZGVwdGgsCiAgICAgICAgICAgIGNvbG91ciA9ICJFdXBob3RpYyAobSkiCiAgICAgICAgICApLAogICAgICAgICAgYWxwaGEgPSAuMiwKICAgICAgICAgIHNpemUgPSAuNQogICAgICAgICkgKwogICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwoCiAgICAgICAgICB2YWx1ZXMgPSBjKAogICAgICAgICAgICAiVGhlcm1vY2xpbmUgKG0pIiA9ICJyZWQiLAogICAgICAgICAgICAiRXVwaG90aWMgKG0pIiA9ICJibGFjayIKICAgICAgICAgICksCiAgICAgICAgICBuYW1lID0gIlpvbmUiCiAgICAgICAgKSArCiAgICAgICAgbmV3X3NjYWxlX2NvbG9yKCkgKwogICAgICAgIGdlb21fcG9pbnQoCiAgICAgICAgICBkYXRhID0gbWVsdChkYXRhXzIwMThfZmlsdGVyWywgLiguaWQsIGRhdGUsIGdldChpKSldLCBpZC52YXJzID0gYygiLmlkIiwgImRhdGUiKSksCiAgICAgICAgICBhZXMoCiAgICAgICAgICAgIHggPSBhcy5EYXRlKGRhdGUpLAogICAgICAgICAgICB5ID0gLXZhbHVlLAogICAgICAgICAgICBjb2wgPSAuaWQKICAgICAgICAgICksCiAgICAgICAgICBhbHBoYSA9IDEgLyAxMCwKICAgICAgICAgIHNpemUgPSAuNSwKICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UKICAgICAgICApICsKICAgICAgICBmYWNldF93cmFwKC4gfiAuaWQsIHNjYWxlcyA9ICJmcmVlIikgKwogICAgICAgIHNjYWxlX3hfZGF0ZShkYXRlX2xhYmVscyA9ICIlbS8lWSIpICsKICAgICAgICBsYWJzKHggPSAiRGF0ZSIsIHkgPSAiTWF4aW11bSBEZXB0aCAobSkiKSArCiAgICAgICAgdGhlbWVfampvKCkgKwogICAgICAgIHRoZW1lKAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iCiAgICAgICAgKQogICAgKQogICAgY2F0KCI8YmxvY2txdW90ZT4gQ29uc2lkZXJpbmcgYGluZF8yMDE4MDc0YCBoYXMgc2xpZ2h0bHkgZGlmZmVyZW50IHZhbHVlcyB0aGFuIG90aGVyIGluZGl2aWR1YWxzIGZvciB0aGUgdGhlcm1vY2xpbmUgZGVwdGgsIGl0IHdvdWxkIGJlIGludGVyZXN0aW5nIHRvIHNlZSB3aGVyZSB0aGUgYW5pbWFsIHdlbnQuIDwvYmxvY2txdW90ZT4iKQogIH0gZWxzZSBpZiAoaSA9PSAiZHJpZnRyYXRlIikgewogICAgcHJpbnQoCiAgICAgIGdncGxvdCgKICAgICAgICBkYXRhID0gbWVsdChkYXRhXzIwMThfZmlsdGVyWywgLiguaWQsIGRhdGUsIGdldChpKSwgZGl2ZXR5cGUpXSwgaWQudmFycyA9IGMoIi5pZCIsICJkYXRlIiwgImRpdmV0eXBlIikpLAogICAgICAgIGFlcygKICAgICAgICAgIHggPSBhcy5EYXRlKGRhdGUpLAogICAgICAgICAgeSA9IHZhbHVlLAogICAgICAgICAgY29sID0gZGl2ZXR5cGUKICAgICAgICApCiAgICAgICkgKwogICAgICAgIGdlb21fcG9pbnQoCiAgICAgICAgICBhbHBoYSA9IDEgLyAxMCwKICAgICAgICAgIHNpemUgPSAuNQogICAgICAgICkgKwogICAgICAgIGZhY2V0X3dyYXAoLiB+IC5pZCwgc2NhbGVzID0gImZyZWUiKSArCiAgICAgICAgc2NhbGVfeF9kYXRlKGRhdGVfbGFiZWxzID0gIiVtLyVZIikgKwogICAgICAgIGxhYnMoeCA9ICJEYXRlIiwgeSA9ICJEcmlmdCBSYXRlICdtL3MiLCBjb2wgPSAiRGl2ZSBUeXBlIikgKwogICAgICAgIHRoZW1lX2pqbygpICsKICAgICAgICB0aGVtZSgKICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksCiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIgogICAgICAgICkgKwogICAgICAgIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdCgKICAgICAgICAgIHNpemUgPSA3LAogICAgICAgICAgYWxwaGEgPSAxCiAgICAgICAgKSkpCiAgICApCiAgfSBlbHNlIHsKICAgIHByaW50KAogICAgICBnZ3Bsb3QoCiAgICAgICAgZGF0YSA9IG1lbHQoZGF0YV8yMDE4X2ZpbHRlclssIC4oLmlkLCBkYXRlLCBnZXQoaSkpXSwgaWQudmFycyA9IGMoIi5pZCIsICJkYXRlIikpLAogICAgICAgIGFlcygKICAgICAgICAgIHggPSBhcy5EYXRlKGRhdGUpLAogICAgICAgICAgeSA9IHZhbHVlLAogICAgICAgICAgY29sID0gLmlkCiAgICAgICAgKQogICAgICApICsKICAgICAgICBnZW9tX3BvaW50KAogICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgICAgICAgIGFscGhhID0gMSAvIDEwLAogICAgICAgICAgc2l6ZSA9IC41CiAgICAgICAgKSArCiAgICAgICAgZmFjZXRfd3JhcCguIH4gLmlkLCBzY2FsZXMgPSAiZnJlZSIpICsKICAgICAgICBzY2FsZV94X2RhdGUoZGF0ZV9sYWJlbHMgPSAiJW0vJVkiKSArCiAgICAgICAgbGFicyh4ID0gIkRhdGUiLCB5ID0gaSkgKwogICAgICAgIHRoZW1lX2pqbygpICsKICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQogICAgKQogIH0KICAKICBjYXQoIlxuIFxuIikKfQpgYGAKCiMjIyMgey51bmxpc3RlZCAudW5udW1iZXJlZCAudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfQoKYGBge3IsIHJlc3VsdHM9J2FzaXMnLCBjYWNoZT1UUlVFLCBlY2hvPUZBTFNFfQpmb3IgKGkgaW4gbmFtZXNfZGlzcGxheSkgewogIGNhdCgiIyMjIyMiLCBpLCAiey51bmxpc3RlZCAudW5udW1iZXJlZH0gXG4iKQogIGlmIChpID09ICJtYXhkZXB0aCIpIHsKICAgIHByaW50KAogICAgICBnZ3Bsb3QoKSArCiAgICAgICAgZ2VvbV9wb2ludCgKICAgICAgICAgIGRhdGEgPSBkYXRhXzIwMThfZmlsdGVyWywgLigKICAgICAgICAgICAgLmlkLAogICAgICAgICAgICBkYXRlLAogICAgICAgICAgICB0aGVybW9jbGluZWRlcHRoCiAgICAgICAgICApXSwKICAgICAgICAgIGFlcygKICAgICAgICAgICAgeCA9IGFzLkRhdGUoZGF0ZSksCiAgICAgICAgICAgIHkgPSAtdGhlcm1vY2xpbmVkZXB0aCwKICAgICAgICAgICAgY29sb3VyID0gIlRoZXJtb2NsaW5lIChtKSIKICAgICAgICAgICksCiAgICAgICAgICBhbHBoYSA9IC4yLAogICAgICAgICAgc2l6ZSA9IC41CiAgICAgICAgKSArCiAgICAgICAgZ2VvbV9wb2ludCgKICAgICAgICAgIGRhdGEgPSBkYXRhXzIwMThfZmlsdGVyWywgLigKICAgICAgICAgICAgLmlkLAogICAgICAgICAgICBkYXRlLAogICAgICAgICAgICBldXBob3RpY2RlcHRoCiAgICAgICAgICApXSwKICAgICAgICAgIGFlcygKICAgICAgICAgICAgeCA9IGFzLkRhdGUoZGF0ZSksCiAgICAgICAgICAgIHkgPSAtZXVwaG90aWNkZXB0aCwKICAgICAgICAgICAgY29sb3VyID0gIkV1cGhvdGljIChtKSIKICAgICAgICAgICksCiAgICAgICAgICBhbHBoYSA9IC4yLAogICAgICAgICAgc2l6ZSA9IC41CiAgICAgICAgKSArCiAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCgKICAgICAgICAgIHZhbHVlcyA9IGMoCiAgICAgICAgICAgICJUaGVybW9jbGluZSAobSkiID0gInJlZCIsCiAgICAgICAgICAgICJFdXBob3RpYyAobSkiID0gImJsYWNrIgogICAgICAgICAgKSwKICAgICAgICAgIG5hbWUgPSAiWm9uZSIKICAgICAgICApICsKICAgICAgICBuZXdfc2NhbGVfY29sb3IoKSArCiAgICAgICAgZ2VvbV9wb2ludCgKICAgICAgICAgIGRhdGEgPSBtZWx0KGRhdGFfMjAxOF9maWx0ZXJbLCAuKC5pZCwgZGF0ZSwgZ2V0KGkpKV0sIGlkLnZhcnMgPSBjKCIuaWQiLCAiZGF0ZSIpKSwKICAgICAgICAgIGFlcygKICAgICAgICAgICAgeCA9IGFzLkRhdGUoZGF0ZSksCiAgICAgICAgICAgIHkgPSAtdmFsdWUsCiAgICAgICAgICAgIGNvbCA9IC5pZAogICAgICAgICAgKSwKICAgICAgICAgIGFscGhhID0gMSAvIDEwLAogICAgICAgICAgc2l6ZSA9IC41LAogICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRQogICAgICAgICkgKwogICAgICAgIGZhY2V0X3dyYXAoLiB+IC5pZCwgc2NhbGVzID0gImZyZWUiKSArCiAgICAgICAgc2NhbGVfeF9kYXRlKGRhdGVfbGFiZWxzID0gIiVtLyVZIikgKwogICAgICAgIGxhYnMoeCA9ICJEYXRlIiwgeSA9ICJNYXhpbXVtIERlcHRoIChtKSIpICsKICAgICAgICB0aGVtZV9qam8oKSArCiAgICAgICAgdGhlbWUoCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLAogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIKICAgICAgICApCiAgICApCiAgICBjYXQoIjxibG9ja3F1b3RlPiBDb25zaWRlcmluZyBgaW5kXzIwMTgwNzRgIGhhcyBzbGlnaHRseSBkaWZmZXJlbnQgdmFsdWVzIHRoYW4gb3RoZXIgaW5kaXZpZHVhbHMgZm9yIHRoZSB0aGVybW9jbGluZSBkZXB0aCwgaXQgd291bGQgYmUgaW50ZXJlc3RpbmcgdG8gc2VlIHdoZXJlIHRoZSBhbmltYWwgd2VudC4gPC9ibG9ja3F1b3RlPiIpCiAgfSBlbHNlIGlmIChpID09ICJkcmlmdHJhdGUiKSB7CiAgICBwcmludCgKICAgICAgZ2dwbG90KAogICAgICAgIGRhdGEgPSBtZWx0KGRhdGFfMjAxOF9maWx0ZXJbLCAuKC5pZCwgZGF0ZSwgZ2V0KGkpLCBkaXZldHlwZSldLCBpZC52YXJzID0gYygiLmlkIiwgImRhdGUiLCAiZGl2ZXR5cGUiKSksCiAgICAgICAgYWVzKAogICAgICAgICAgeCA9IGFzLkRhdGUoZGF0ZSksCiAgICAgICAgICB5ID0gdmFsdWUsCiAgICAgICAgICBjb2wgPSBkaXZldHlwZQogICAgICAgICkKICAgICAgKSArCiAgICAgICAgZ2VvbV9wb2ludCgKICAgICAgICAgIGFscGhhID0gMSAvIDEwLAogICAgICAgICAgc2l6ZSA9IC41CiAgICAgICAgKSArCiAgICAgICAgZmFjZXRfd3JhcCguIH4gLmlkLCBzY2FsZXMgPSAiZnJlZSIpICsKICAgICAgICBzY2FsZV94X2RhdGUoZGF0ZV9sYWJlbHMgPSAiJW0vJVkiKSArCiAgICAgICAgbGFicyh4ID0gIkRhdGUiLCB5ID0gIkRyaWZ0IFJhdGUgJ20vcyIsIGNvbCA9ICJEaXZlIFR5cGUiKSArCiAgICAgICAgdGhlbWVfampvKCkgKwogICAgICAgIHRoZW1lKAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iCiAgICAgICAgKSArCiAgICAgICAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KAogICAgICAgICAgc2l6ZSA9IDcsCiAgICAgICAgICBhbHBoYSA9IDEKICAgICAgICApKSkKICAgICkKICB9IGVsc2UgewogICAgcHJpbnQoCiAgICAgIGdncGxvdCgKICAgICAgICBkYXRhID0gbWVsdChkYXRhXzIwMThfZmlsdGVyWywgLiguaWQsIGRhdGUsIGdldChpKSldLCBpZC52YXJzID0gYygiLmlkIiwgImRhdGUiKSksCiAgICAgICAgYWVzKAogICAgICAgICAgeCA9IGFzLkRhdGUoZGF0ZSksCiAgICAgICAgICB5ID0gdmFsdWUsCiAgICAgICAgICBjb2wgPSAuaWQKICAgICAgICApCiAgICAgICkgKwogICAgICAgIGdlb21fcG9pbnQoCiAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFLAogICAgICAgICAgYWxwaGEgPSAxIC8gMTAsCiAgICAgICAgICBzaXplID0gLjUKICAgICAgICApICsKICAgICAgICBmYWNldF93cmFwKC4gfiAuaWQsIHNjYWxlcyA9ICJmcmVlIikgKwogICAgICAgIHNjYWxlX3hfZGF0ZShkYXRlX2xhYmVscyA9ICIlbS8lWSIpICsKICAgICAgICBsYWJzKHggPSAiRGF0ZSIsIHkgPSBpKSArCiAgICAgICAgdGhlbWVfampvKCkgKwogICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCiAgICApCiAgfQogIAogIGNhdCgiXG4gXG4iKQp9CmBgYAoKIyMjIyB7LnVubGlzdGVkIC51bm51bWJlcmVkfQoKPiBGZXcgcXVlc3Rpb25zLCB0aGF0IEkgc2hvdWxkIGxvb2sgaW50byBpdDoKICA+CiAgPiAqIGlzIHRoZSBiaW1vZGFsIGRpc3RyaWJ1dGlvbiBvZiBgZGR1cmF0aW9uYCwgYGRlc2N0aW1lYCBkdWUgdG8gbnljdGhlbWVyYWwgbWlncmF0aW9uPwogID4gKiBpcyB0aGUgYmltb2RhbCBkaXN0cmlidXRpb24gb2YgYGRlc2NyYXRlYCAoZXNwZWNpYWxseSBmb3IgYGluZDIwMTgwNzBgIGFuZCBgaW5kXzIwMTgwNzJgKSBkdWUgdG8gZHJpZnQgZGl2ZT8KICA+ICogaXMgYGxpZ2h0YXRib3R0YCBjb3VsZCBiZSB1c2VkIHRvIGlkZW50aWZ5IGJpb2x1bWluZXNjZW5jZSwgY2F1c2UgaXQgc2VlbXMgdGhlcmUgaXMgYSBsb3QgZ29pbmcgb24gYXQgdGhlIGJvdHRvbT8KICA+ICogYXJlIHRoZSB2YXJpYXRpb25zIG9ic2VydmVkIGZvciBgbGlnaHRhdHN1cmZgIGlzIGR1ZSB0byBtb29uIGN5Y2xlPwogID4gKiBub3Qgc3VyZSB3aHkgaXMgdGhlcmUgYSBiaW1vZGFsIGRpc3RyaWJ1dGlvbiBvZiBgdGVtcGF0Ym90dGAhCiAgPiAqIGBkcmlmcmF0ZWAgdGhhdCBvbmUgaXMgYXdlc29tZSEgVGhhbmtzIHRvIGBkaXZldHlwZWAgd2UgY2FuIGNsZWFybHkgc2VlIGEgcGF0dGVybiBvZiBob3cgZHJpZnRyYXRlIChhbmQgc28gYnVveWFuY3kpIGNoYW5nZSBhY2NvcmRpbmcgdGltZS4KPiAqIHRoZSBiaW1vZGFsIGRpc3RyaWJ1dGlvbiBvZiBgdmVydGljYWxzcGVlZDkwYCBhbmQgYHZlcnRpY2Fsc3BlZWQ5NWAgc2hvdWxkIGJlIGR1ZSB0byBkcmlmdCBkaXZlLgoKYGBge3IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0KIyBzYW1lIHBsb3Qgd2l0aCBhIGNvbG9yZWQgZm9yIHRoZSBwaGFzZSBvZiB0aGUgZGF5CmZvciAoaSBpbiBuYW1lc19kaXNwbGF5KSB7CiAgY2F0KCIjIyMjIyIsIGksICJ7LX0gXG4iKQogIHByaW50KAogICAgZ2dwbG90KAogICAgICBkYXRhID0gbWVsdChkYXRhXzIwMThfZmlsdGVyWywgLiguaWQsIGRhdGUsIGdldChpKSwgcGhhc2UpXSwKICAgICAgICAgICAgICAgICAgaWQudmFycyA9IGMoCiAgICAgICAgICAgICAgICAgICAgIi5pZCIsCiAgICAgICAgICAgICAgICAgICAgImRhdGUiLAogICAgICAgICAgICAgICAgICAgICJwaGFzZSIKICAgICAgICAgICAgICAgICAgKQogICAgICApLAogICAgICBhZXMoCiAgICAgICAgeCA9IGFzLkRhdGUoZGF0ZSksCiAgICAgICAgeSA9IHZhbHVlLAogICAgICAgIGNvbCA9IHBoYXNlCiAgICAgICkKICAgICkgKwogICAgICBnZW9tX3BvaW50KAogICAgICAgIGFscGhhID0gMSAvIDEwLAogICAgICAgIHNpemUgPSAuNQogICAgICApICsKICAgICAgZmFjZXRfd3JhcCguIH4gLmlkLCBzY2FsZXMgPSAiZnJlZSIpICsKICAgICAgc2NhbGVfeF9kYXRlKGRhdGVfbGFiZWxzID0gIiVtLyVZIikgKwogICAgICBsYWJzKHggPSAiRGF0ZSIsIHkgPSBpKSArCiAgICAgIHRoZW1lX2pqbygpICsKICAgICAgdGhlbWUoCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIgogICAgICApICsKICAgICAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KAogICAgICAgIHNpemUgPSA3LAogICAgICAgIGFscGhhID0gMQogICAgICApKSkKICApCiAgY2F0KCJcbiBcbiIpCn0KYGBgCgojIyMjIHsudW5saXN0ZWQgLnVubnVtYmVyZWQgLnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30KCmBgYHtyLCByZXN1bHRzPSdhc2lzJywgY2FjaGU9VFJVRSwgZWNobz1GQUxTRX0KIyBzYW1lIHBsb3Qgd2l0aCBhIGNvbG9yZWQgZm9yIHRoZSBwaGFzZSBvZiB0aGUgZGF5CmZvciAoaSBpbiBuYW1lc19kaXNwbGF5KSB7CiAgY2F0KCIjIyMjIyIsIGksICJ7LX0gXG4iKQogIHByaW50KAogICAgZ2dwbG90KAogICAgICBkYXRhID0gbWVsdChkYXRhXzIwMThfZmlsdGVyWywgLiguaWQsIGRhdGUsIGdldChpKSwgcGhhc2UpXSwKICAgICAgICAgICAgICAgICAgaWQudmFycyA9IGMoCiAgICAgICAgICAgICAgICAgICAgIi5pZCIsCiAgICAgICAgICAgICAgICAgICAgImRhdGUiLAogICAgICAgICAgICAgICAgICAgICJwaGFzZSIKICAgICAgICAgICAgICAgICAgKQogICAgICApLAogICAgICBhZXMoCiAgICAgICAgeCA9IGFzLkRhdGUoZGF0ZSksCiAgICAgICAgeSA9IHZhbHVlLAogICAgICAgIGNvbCA9IHBoYXNlCiAgICAgICkKICAgICkgKwogICAgICBnZW9tX3BvaW50KAogICAgICAgIGFscGhhID0gMSAvIDEwLAogICAgICAgIHNpemUgPSAuNQogICAgICApICsKICAgICAgZmFjZXRfd3JhcCguIH4gLmlkLCBzY2FsZXMgPSAiZnJlZSIpICsKICAgICAgc2NhbGVfeF9kYXRlKGRhdGVfbGFiZWxzID0gIiVtLyVZIikgKwogICAgICBsYWJzKHggPSAiRGF0ZSIsIHkgPSBpKSArCiAgICAgIHRoZW1lX2pqbygpICsKICAgICAgdGhlbWUoCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIgogICAgICApICsKICAgICAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KAogICAgICAgIHNpemUgPSA3LAogICAgICAgIGFscGhhID0gMQogICAgICApKSkKICApCiAgY2F0KCJcbiBcbiIpCn0KYGBgCgoKIyMjIEFsbCBWYXJpYWJsZXMgZHVyaW5nIHRoZSBmaXJzdCBtb250aAoKYGBge3IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0KZm9yIChpIGluIG5hbWVzX2Rpc3BsYXkpIHsKICBjYXQoIiMjIyMjIiwgaSwgInsudW5saXN0ZWQgLnVubnVtYmVyZWR9IFxuIikKICBpZiAoaSA9PSAibWF4ZGVwdGgiKSB7CiAgICBwcmludCgKICAgICAgZ2dwbG90KCkgKwogICAgICAgIGdlb21fcG9pbnQoCiAgICAgICAgICBkYXRhID0gZGF0YV8yMDE4X2ZpbHRlcltkYXlfZGVwYXJ0dXJlIDwgMzIsIC4oCiAgICAgICAgICAgIC5pZCwKICAgICAgICAgICAgZGF5X2RlcGFydHVyZSwKICAgICAgICAgICAgdGhlcm1vY2xpbmVkZXB0aAogICAgICAgICAgKV0sCiAgICAgICAgICBhZXMoCiAgICAgICAgICAgIHggPSBkYXlfZGVwYXJ0dXJlLAogICAgICAgICAgICB5ID0gLXRoZXJtb2NsaW5lZGVwdGgsCiAgICAgICAgICAgIGNvbG91ciA9ICJUaGVybW9jbGluZSAobSkiLAogICAgICAgICAgICBncm91cCA9IGRheV9kZXBhcnR1cmUKICAgICAgICAgICksCiAgICAgICAgICBhbHBoYSA9IC4yLAogICAgICAgICAgc2l6ZSA9IC41CiAgICAgICAgKSArCiAgICAgICAgZ2VvbV9wb2ludCgKICAgICAgICAgIGRhdGEgPSBkYXRhXzIwMThfZmlsdGVyW2RheV9kZXBhcnR1cmUgPCAzMiwgLigKICAgICAgICAgICAgLmlkLAogICAgICAgICAgICBkYXlfZGVwYXJ0dXJlLAogICAgICAgICAgICBldXBob3RpY2RlcHRoCiAgICAgICAgICApXSwKICAgICAgICAgIGFlcygKICAgICAgICAgICAgeCA9IGRheV9kZXBhcnR1cmUsCiAgICAgICAgICAgIHkgPSAtZXVwaG90aWNkZXB0aCwKICAgICAgICAgICAgY29sb3VyID0gIkV1cGhvdGljIChtKSIsCiAgICAgICAgICAgIGdyb3VwID0gZGF5X2RlcGFydHVyZQogICAgICAgICAgKSwKICAgICAgICAgIGFscGhhID0gLjIsCiAgICAgICAgICBzaXplID0gLjUKICAgICAgICApICsKICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKAogICAgICAgICAgdmFsdWVzID0gYygKICAgICAgICAgICAgIlRoZXJtb2NsaW5lIChtKSIgPSAicmVkIiwKICAgICAgICAgICAgIkV1cGhvdGljIChtKSIgPSAiYmxhY2siCiAgICAgICAgICApLAogICAgICAgICAgbmFtZSA9ICJab25lIgogICAgICAgICkgKwogICAgICAgIG5ld19zY2FsZV9jb2xvcigpICsKICAgICAgICBnZW9tX2JveHBsb3QoCiAgICAgICAgICBkYXRhID0gbWVsdChkYXRhXzIwMThfZmlsdGVyW2RheV9kZXBhcnR1cmUgPCAzMiwgLiguaWQsIGRheV9kZXBhcnR1cmUsIGdldChpKSldLCBpZC52YXJzID0gYygiLmlkIiwgImRheV9kZXBhcnR1cmUiKSksCiAgICAgICAgICBhZXMoCiAgICAgICAgICAgIHggPSBkYXlfZGVwYXJ0dXJlLAogICAgICAgICAgICB5ID0gLXZhbHVlLAogICAgICAgICAgICBjb2wgPSAuaWQsCiAgICAgICAgICAgIGdyb3VwID0gZGF5X2RlcGFydHVyZQogICAgICAgICAgKSwKICAgICAgICAgIGFscGhhID0gMSAvIDEwLAogICAgICAgICAgc2l6ZSA9IC41LAogICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRQogICAgICAgICkgKwogICAgICAgIGZhY2V0X3dyYXAoLiB+IC5pZCwgc2NhbGVzID0gImZyZWUiKSArCiAgICAgICAgbGFicyh4ID0gIiMgZGF5cyBzaW5jZSBkZXBhcnR1cmUiLCB5ID0gIk1heGltdW0gRGVwdGggKG0pIikgKwogICAgICAgIHRoZW1lX2pqbygpICsKICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKICAgICkKICB9IGVsc2UgewogICAgcHJpbnQoCiAgICAgIGdncGxvdCgKICAgICAgICBkYXRhID0gbWVsdChkYXRhXzIwMThfZmlsdGVyW2RheV9kZXBhcnR1cmUgPCAzMiwgLiguaWQsIGRheV9kZXBhcnR1cmUsIGdldChpKSldLCBpZC52YXJzID0gYygiLmlkIiwgImRheV9kZXBhcnR1cmUiKSksCiAgICAgICAgYWVzKAogICAgICAgICAgeCA9IGRheV9kZXBhcnR1cmUsCiAgICAgICAgICB5ID0gdmFsdWUsCiAgICAgICAgICBjb2xvciA9IC5pZCwKICAgICAgICAgIGdyb3VwID0gZGF5X2RlcGFydHVyZQogICAgICAgICkKICAgICAgKSArCiAgICAgICAgZ2VvbV9ib3hwbG90KAogICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgICAgICAgIGFscGhhID0gMSAvIDEwLAogICAgICAgICAgc2l6ZSA9IC41CiAgICAgICAgKSArCiAgICAgICAgZmFjZXRfd3JhcCguIH4gLmlkLCBzY2FsZXMgPSAiZnJlZSIpICsKICAgICAgICBsYWJzKHggPSAiIyBkYXlzIHNpbmNlIGRlcGFydHVyZSIsIHkgPSBpKSArCiAgICAgICAgdGhlbWVfampvKCkKICAgICkKICB9CiAgY2F0KCJcbiBcbiIpCn0KYGBgCgojIyMjIHsudW5saXN0ZWQgLnVubnVtYmVyZWQgLnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30KCmBgYHtyLCByZXN1bHRzPSdhc2lzJywgY2FjaGU9VFJVRSwgZWNobz1GQUxTRX0KZm9yIChpIGluIG5hbWVzX2Rpc3BsYXkpIHsKICBjYXQoIiMjIyMjIiwgaSwgInsudW5saXN0ZWQgLnVubnVtYmVyZWR9IFxuIikKICBpZiAoaSA9PSAibWF4ZGVwdGgiKSB7CiAgICBwcmludCgKICAgICAgZ2dwbG90KCkgKwogICAgICAgIGdlb21fcG9pbnQoCiAgICAgICAgICBkYXRhID0gZGF0YV8yMDE4X2ZpbHRlcltkYXlfZGVwYXJ0dXJlIDwgMzIsIC4oCiAgICAgICAgICAgIC5pZCwKICAgICAgICAgICAgZGF5X2RlcGFydHVyZSwKICAgICAgICAgICAgdGhlcm1vY2xpbmVkZXB0aAogICAgICAgICAgKV0sCiAgICAgICAgICBhZXMoCiAgICAgICAgICAgIHggPSBkYXlfZGVwYXJ0dXJlLAogICAgICAgICAgICB5ID0gLXRoZXJtb2NsaW5lZGVwdGgsCiAgICAgICAgICAgIGNvbG91ciA9ICJUaGVybW9jbGluZSAobSkiLAogICAgICAgICAgICBncm91cCA9IGRheV9kZXBhcnR1cmUKICAgICAgICAgICksCiAgICAgICAgICBhbHBoYSA9IC4yLAogICAgICAgICAgc2l6ZSA9IC41CiAgICAgICAgKSArCiAgICAgICAgZ2VvbV9wb2ludCgKICAgICAgICAgIGRhdGEgPSBkYXRhXzIwMThfZmlsdGVyW2RheV9kZXBhcnR1cmUgPCAzMiwgLigKICAgICAgICAgICAgLmlkLAogICAgICAgICAgICBkYXlfZGVwYXJ0dXJlLAogICAgICAgICAgICBldXBob3RpY2RlcHRoCiAgICAgICAgICApXSwKICAgICAgICAgIGFlcygKICAgICAgICAgICAgeCA9IGRheV9kZXBhcnR1cmUsCiAgICAgICAgICAgIHkgPSAtZXVwaG90aWNkZXB0aCwKICAgICAgICAgICAgY29sb3VyID0gIkV1cGhvdGljIChtKSIsCiAgICAgICAgICAgIGdyb3VwID0gZGF5X2RlcGFydHVyZQogICAgICAgICAgKSwKICAgICAgICAgIGFscGhhID0gLjIsCiAgICAgICAgICBzaXplID0gLjUKICAgICAgICApICsKICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKAogICAgICAgICAgdmFsdWVzID0gYygKICAgICAgICAgICAgIlRoZXJtb2NsaW5lIChtKSIgPSAicmVkIiwKICAgICAgICAgICAgIkV1cGhvdGljIChtKSIgPSAiYmxhY2siCiAgICAgICAgICApLAogICAgICAgICAgbmFtZSA9ICJab25lIgogICAgICAgICkgKwogICAgICAgIG5ld19zY2FsZV9jb2xvcigpICsKICAgICAgICBnZW9tX2JveHBsb3QoCiAgICAgICAgICBkYXRhID0gbWVsdChkYXRhXzIwMThfZmlsdGVyW2RheV9kZXBhcnR1cmUgPCAzMiwgLiguaWQsIGRheV9kZXBhcnR1cmUsIGdldChpKSldLCBpZC52YXJzID0gYygiLmlkIiwgImRheV9kZXBhcnR1cmUiKSksCiAgICAgICAgICBhZXMoCiAgICAgICAgICAgIHggPSBkYXlfZGVwYXJ0dXJlLAogICAgICAgICAgICB5ID0gLXZhbHVlLAogICAgICAgICAgICBjb2wgPSAuaWQsCiAgICAgICAgICAgIGdyb3VwID0gZGF5X2RlcGFydHVyZQogICAgICAgICAgKSwKICAgICAgICAgIGFscGhhID0gMSAvIDEwLAogICAgICAgICAgc2l6ZSA9IC41LAogICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRQogICAgICAgICkgKwogICAgICAgIGZhY2V0X3dyYXAoLiB+IC5pZCwgc2NhbGVzID0gImZyZWUiKSArCiAgICAgICAgbGFicyh4ID0gIiMgZGF5cyBzaW5jZSBkZXBhcnR1cmUiLCB5ID0gIk1heGltdW0gRGVwdGggKG0pIikgKwogICAgICAgIHRoZW1lX2pqbygpICsKICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKICAgICkKICB9IGVsc2UgewogICAgcHJpbnQoCiAgICAgIGdncGxvdCgKICAgICAgICBkYXRhID0gbWVsdChkYXRhXzIwMThfZmlsdGVyW2RheV9kZXBhcnR1cmUgPCAzMiwgLiguaWQsIGRheV9kZXBhcnR1cmUsIGdldChpKSldLCBpZC52YXJzID0gYygiLmlkIiwgImRheV9kZXBhcnR1cmUiKSksCiAgICAgICAgYWVzKAogICAgICAgICAgeCA9IGRheV9kZXBhcnR1cmUsCiAgICAgICAgICB5ID0gdmFsdWUsCiAgICAgICAgICBjb2xvciA9IC5pZCwKICAgICAgICAgIGdyb3VwID0gZGF5X2RlcGFydHVyZQogICAgICAgICkKICAgICAgKSArCiAgICAgICAgZ2VvbV9ib3hwbG90KAogICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgICAgICAgIGFscGhhID0gMSAvIDEwLAogICAgICAgICAgc2l6ZSA9IC41CiAgICAgICAgKSArCiAgICAgICAgZmFjZXRfd3JhcCguIH4gLmlkLCBzY2FsZXMgPSAiZnJlZSIpICsKICAgICAgICBsYWJzKHggPSAiIyBkYXlzIHNpbmNlIGRlcGFydHVyZSIsIHkgPSBpKSArCiAgICAgICAgdGhlbWVfampvKCkKICAgICkKICB9CiAgY2F0KCJcbiBcbiIpCn0KYGBgCgojIyMjIHsudW5saXN0ZWQgLnVubnVtYmVyZWR9CgpgYGB7ciwgZXZhbD1GQUxTRSwgaW5jbHVkZT1UUlVFfQpmb3IgKGkgaW4gbmFtZXNfZGlzcGxheSkgewogIGNhdCgiIyMjIyMiLCBpLCAiey51bmxpc3RlZCAudW5udW1iZXJlZH0gXG4iKQogIHByaW50KAogICAgZ2dwbG90KAogICAgICBkYXRhID0gbWVsdChkYXRhXzIwMThfZmlsdGVyWwogICAgICAgIGRheV9kZXBhcnR1cmUgPCAzMiwKICAgICAgICAuKC5pZCwgZGF5X2RlcGFydHVyZSwgZ2V0KGkpLCBwaGFzZSkKICAgICAgXSwKICAgICAgaWQudmFycyA9IGMoIi5pZCIsICJkYXlfZGVwYXJ0dXJlIiwgInBoYXNlIikKICAgICAgKSwKICAgICAgYWVzKAogICAgICAgIHggPSBkYXlfZGVwYXJ0dXJlLAogICAgICAgIHkgPSB2YWx1ZSwKICAgICAgICBjb2xvciA9IHBoYXNlLAogICAgICAgIGdyb3VwID0gaW50ZXJhY3Rpb24oZGF5X2RlcGFydHVyZSwgcGhhc2UpLAogICAgICApCiAgICApICsKICAgICAgZ2VvbV9ib3hwbG90KAogICAgICAgIGFscGhhID0gMSAvIDEwLAogICAgICAgIHNpemUgPSAuNQogICAgICApICsKICAgICAgZmFjZXRfd3JhcCguIH4gLmlkLCBzY2FsZXMgPSAiZnJlZSIpICsKICAgICAgbGFicyh4ID0gIiMgZGF5cyBzaW5jZSBkZXBhcnR1cmUiLCB5ID0gaSkgKwogICAgICB0aGVtZV9qam8oKSArCiAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQogICkKICBjYXQoIlxuIFxuIikKfQpgYGAKCiMjIyMgey51bmxpc3RlZCAudW5udW1iZXJlZCAudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfQoKYGBge3IsIHJlc3VsdHM9J2FzaXMnLCBjYWNoZT1UUlVFLCBlY2hvPUZBTFNFfQpmb3IgKGkgaW4gbmFtZXNfZGlzcGxheSkgewogIGNhdCgiIyMjIyMiLCBpLCAiey51bmxpc3RlZCAudW5udW1iZXJlZH0gXG4iKQogIHByaW50KAogICAgZ2dwbG90KAogICAgICBkYXRhID0gbWVsdChkYXRhXzIwMThfZmlsdGVyWwogICAgICAgIGRheV9kZXBhcnR1cmUgPCAzMiwKICAgICAgICAuKC5pZCwgZGF5X2RlcGFydHVyZSwgZ2V0KGkpLCBwaGFzZSkKICAgICAgXSwKICAgICAgaWQudmFycyA9IGMoIi5pZCIsICJkYXlfZGVwYXJ0dXJlIiwgInBoYXNlIikKICAgICAgKSwKICAgICAgYWVzKAogICAgICAgIHggPSBkYXlfZGVwYXJ0dXJlLAogICAgICAgIHkgPSB2YWx1ZSwKICAgICAgICBjb2xvciA9IHBoYXNlLAogICAgICAgIGdyb3VwID0gaW50ZXJhY3Rpb24oZGF5X2RlcGFydHVyZSwgcGhhc2UpLAogICAgICApCiAgICApICsKICAgICAgZ2VvbV9ib3hwbG90KAogICAgICAgIGFscGhhID0gMSAvIDEwLAogICAgICAgIHNpemUgPSAuNQogICAgICApICsKICAgICAgZmFjZXRfd3JhcCguIH4gLmlkLCBzY2FsZXMgPSAiZnJlZSIpICsKICAgICAgbGFicyh4ID0gIiMgZGF5cyBzaW5jZSBkZXBhcnR1cmUiLCB5ID0gaSkgKwogICAgICB0aGVtZV9qam8oKSArCiAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQogICkKICBjYXQoIlxuIFxuIikKfQpgYGAKCiMjIyMgQ29ycmVsYXRpb24KCkNhbiB3ZSBmaW5kIG5pY2UgY29ycmVsYXRpb24/CiAgCmBgYHtyLCBmaWcuY2FwPSJDb3JyZWxhdGlvbiBtYXRyaXggKGNyb3NzZXMgaW5kaWNhdGUgbm9uIHNpZ25pZmljYW50IGNvcnJlbGF0aW9uKSIsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KIyBjb21wdXRlIGNvcnJlbGF0aW9uCmNvcnJfMjAxOCA8LSByb3VuZChjb3IoZGF0YV8yMDE4X2ZpbHRlclssIG5hbWVzX2Rpc3BsYXksIHdpdGggPSBGXSwKICAgICAgICAgICAgICAgICAgICAgICB1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIgopLCAxKQoKIyByZXBsYWNlIE5BIHZhbHVlIGJ5IDAKY29ycl8yMDE4W2lzLm5hKGNvcnJfMjAxOCldIDwtIDAKCiMgY29tcHV0ZSBwX3ZhbHVlcwpjb3JyX3BfMjAxOCA8LSBjb3JfcG1hdChkYXRhXzIwMThfZmlsdGVyWywgbmFtZXNfZGlzcGxheSwgd2l0aCA9IEZdKQoKIyByZXBsYWNlIE5BIHZhbHVlIGJ5IDAKY29ycl9wXzIwMThbaXMubmEoY29ycl9wXzIwMTgpXSA8LSAxCgojIGRpc3BsYXkKZ2djb3JycGxvdCgKICBjb3JyXzIwMTgsCiAgcC5tYXQgPSBjb3JyX3BfMjAxOCwKICBoYy5vcmRlciA9IFRSVUUsCiAgbWV0aG9kID0gImNpcmNsZSIsCiAgdHlwZSA9ICJsb3dlciIsCiAgZ2d0aGVtZSA9IHRoZW1lX2pqbygpLAogIHNpZy5sZXZlbCA9IDAuMDUsCiAgY29sb3JzID0gIGMoIiMwMEFGQkIiLCAiI0U3QjgwMCIsICIjRkM0RTA3IikKKQpgYGAKCkFub3RoZXIgd2F5IHRvIHNlZSBpdDoKICAKYGBge3J9CiMgZmxhdHRlbiBjb3JyZWxhdGlvbiBtYXRyaXgKY29yX3Jlc3VsdF8yMDE4IDwtIGZsYXRfY29yX21hdChjb3JyXzIwMTgsIGNvcnJfcF8yMDE4KQoKIyBrZWVwIG9ubHkgdGhlIG9uZSBhYm92ZSAuNwpjb3JfcmVzdWx0XzIwMThbY29yID49IC43LCBdW29yZGVyKC1hYnMoY29yKSldICU+JQogIHNhYmxlKGNhcHRpb24gPSAiUGFpcndpc2UgY29ycmVsYXRpb24gYWJvdmUgMC43NSBhbmQgYXNzb2NpYXRlZCBwLXZhbHVlcyIpCmBgYAoKPiBJIGd1ZXNzIG5vdGhpbmcgdW5leHBlY3RlZCBoZXJlLCBJJ2xsIGhhdmUgdG8gY2hlY2sgd2l0aCBQYXRyaWNrIGFib3V0IHRoZSBlZmZpY2llbmN5IDspCgojIyMgRGl2ZSBUeXBlCgpgYGB7ciwgZmlnLmNhcD0iUHJvcG9ydGlvbiBkaXZlIHR5cGVzIn0KIyBkYXRhc2V0IHRvIHBsb3QgcHJvcG9ydGlvbmFsIGFyZWEgcGxvdApkYXRhXzIwMThfZmlsdGVyWywgc3VtX2lkIDo9IC5OLCBieSA9IC4oLmlkLCBkYXlfZGVwYXJ0dXJlKV1bLCBzdW1faWRfZGF5cyA6PSAuTiwgYnkgPSAuKC5pZCwgZGF5X2RlcGFydHVyZSwgZGl2ZXR5cGUpXVssIHByb3AgOj0gc3VtX2lkX2RheXMgLwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bV9pZF0KZGF0YVBsb3QgPC0gdW5pcXVlKGRhdGFfMjAxOF9maWx0ZXJbLCAuKHByb3AsIC5pZCwgZGl2ZXR5cGUsIGRheV9kZXBhcnR1cmUpXSkKCiMgYXJlYSBwbG90CmdncGxvdChkYXRhUGxvdCwgYWVzKAogIHggPSBhcy5udW1lcmljKGRheV9kZXBhcnR1cmUpLAogIHkgPSBwcm9wLAogIGZpbGwgPSBhcy5jaGFyYWN0ZXIoZGl2ZXR5cGUpCikpICsKICBnZW9tX2FyZWEoYWxwaGEgPSAwLjYsIHNpemUgPSAxKSArCiAgZmFjZXRfd3JhcCguaWQgfiAuLCBzY2FsZXMgPSAiZnJlZSIpICsKICB0aGVtZV9qam8oKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBsYWJzKHggPSAiIyBvZiBkYXlzIHNpbmNlIGRlcGFydHVyZSIsIHkgPSAiUHJvcG9ydGlvbiBvZiBkaXZlcyIsIGZpbGwgPSAiRGl2ZSB0eXBlcyIpCmBgYAoKIyMjIERpdmUgZHVyYXRpb24gKnZzLiogTWF4aW11bSBkZXB0aCB7LnRhYnNldH0KCiMjIyMgQ29sb3JlZCBieSBJRAoKYGBge3IsIGZpZy5jYXA9IkRpdmUgZHVyYXRpb24gdnMuIE1heGltdW0gRGVwdGggY29sb3JlZCAyMDE4LWluZGl2aWR1YWxzIn0KIyBwbG90CmdncGxvdChkYXRhID0gZGF0YV8yMDE4X2ZpbHRlciwgYWVzKHkgPSBkZHVyYXRpb24sIHggPSBtYXhkZXB0aCwgY29sID0gLmlkKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IC41LCBhbHBoYSA9IC4xLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZmFjZXRfd3JhcCguaWQgfiAuKSArCiAgbGFicyh4ID0gIk1heGltdW0gZGVwdGggKG0pIiwgeSA9ICJEaXZlIGR1cmF0aW9uIChzKSIpICsKICB0aGVtZV9qam8oKQpgYGAKCiMjIyMgQ29sb3JlZCBieSBEaXZlIFR5cGUKCmBgYHtyLCBmaWcuY2FwPSJEaXZlIGR1cmF0aW9uIHZzLiBNYXhpbXVtIERlcHRoIGNvbG9yZWQgYnkgRGl2ZSBUeXBlIn0KIyBwbG90CmdncGxvdChkYXRhID0gZGF0YV8yMDE4X2ZpbHRlciwgYWVzKHkgPSBkZHVyYXRpb24sIHggPSBtYXhkZXB0aCwgY29sID0gZGl2ZXR5cGUpKSArCiAgZ2VvbV9wb2ludChzaXplID0gLjUsIGFscGhhID0gLjEpICsKICBmYWNldF93cmFwKC5pZCB+IC4pICsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDUsIGFscGhhID0gMSkpKSArCiAgbGFicyh4ID0gIk1heGltdW0gZGVwdGggKG0pIiwgeSA9ICJEaXZlIGR1cmF0aW9uIChzKSIpICsKICB0aGVtZV9qam8oKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCmBgYAoKIyMjIyBDb2xvcmVkIGJ5ICMgZGF5cyBzaW5jZSBkZXBhcnR1cmUKCmBgYHtyLCBmaWcuY2FwPSJEaXZlIGR1cmF0aW9uIHZzLiBNYXhpbXVtIERlcHRoIGNvbG9yZWQgYnkgIyBkYXlzIHNpbmNlIGRlcGFydHVyZSJ9CiMgcGxvdApnZ3Bsb3QoZGF0YSA9IGRhdGFfMjAxOF9maWx0ZXJbLCBwcm9wX3RyYWNrIDo9IChkYXlfZGVwYXJ0dXJlICogMTAwKSAvIG1heChkYXlfZGVwYXJ0dXJlKSwgYnkgPSAuaWRdLCBhZXMoeSA9IGRkdXJhdGlvbiwgeCA9IG1heGRlcHRoLCBjb2wgPSBwcm9wX3RyYWNrKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IC41LCBhbHBoYSA9IC4xKSArCiAgZmFjZXRfd3JhcCguaWQgfiAuKSArCiAgbGFicyh4ID0gIk1heGltdW0gZGVwdGggKG0pIiwgeSA9ICJEaXZlIGR1cmF0aW9uIChzKSIsIGNvbCA9ICJQcm9wb3J0aW9uIG9mIGNvbXBsZXRlZCB0cmFjayAoJSkiKSArCiAgc2NhbGVfY29sb3JfY29udGludW91cyh0eXBlID0gInZpcmlkaXMiKSArCiAgdGhlbWVfampvKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQpgYGAKCiMjIyMgQ29sb3JlZCBieSBwaGFzZXMgb2YgZGF5CgpgYGB7ciwgZmlnLmNhcD0iRGl2ZSBkdXJhdGlvbiB2cy4gTWF4aW11bSBEZXB0aCBjb2xvcmVkIGJ5IHBoYXNlcyBvZiB0aGUgZGF5In0KIyBwbG90CmdncGxvdChkYXRhID0gZGF0YV8yMDE4X2ZpbHRlciwgYWVzKHkgPSBkZHVyYXRpb24sIHggPSBtYXhkZXB0aCwgY29sID0gcGhhc2UpKSArCiAgZ2VvbV9wb2ludChzaXplID0gLjUsIGFscGhhID0gLjEpICsKICBmYWNldF93cmFwKC5pZCB+IC4pICsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDUsIGFscGhhID0gMSkpKSArCiAgbGFicyh4ID0gIk1heGltdW0gZGVwdGggKG0pIiwgeSA9ICJEaXZlIGR1cmF0aW9uIChzKSIsIGNvbCA9ICJQaGFzZXMgb2YgdGhlIGRheSIpICsKICB0aGVtZV9qam8oKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCmBgYAoKPiBUaGVyZSBzZWVtcyB0byBiZSBhICpwYXRjaCogZm9yIGhpZ2ggZGVwdGhzIChlc3BlY2lhbGx5IHZpc2libGUgZm9yIGBpbmQyMDE4MDcwYCksIGJ1dCBJIGRvbid0IGtub3cgd2hhdCBpdCBjb3VsZCBiZSBsaW5rZWQgdG8uLi4KCiMjIyBEcmlmdCBSYXRlCgo+IEluIHRoZSBmb2xsb3dpbmcgZ3JhcGhzOgo+Cj4gKiBgZHJpZnRyYXRlYCBpcyBjYWxjdWxhdGVkIHVzaW5nIG9ubHkgYGRpdmV0eXBlID09ICIyOiBkcmlmdCJgCj4gKiB3aGVyZWFzIGFsbCB0aGUgb3RoZXJzIHZhcmlhYmxlcyBhcmUgY2FsY3VsYXRlZCBhbGwgZGl2ZXMgY29uc2lkZXJlZAoKYGBge3J9CiMgYnVpbGQgZGF0YXNldApkYXRhUGxvdCA8LSBkYXRhXzIwMThfZmlsdGVyW2RpdmV0eXBlID09ICIyOiBkcmlmdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBtZWRpYW4gZHJpZnQgcmF0ZSBmb3IgZHJpZnQgZGl2ZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4oZHJpZnRyYXRlID0gbWVkaWFuKGRyaWZ0cmF0ZSwgbmEucm0gPSBUKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAuKC5pZCwgZGF5X2RlcGFydHVyZSkKXVtkYXRhXzIwMThfZmlsdGVyWywKICAgICAgICAgICAgICAgICAgIC4oCiAgICAgICAgICAgICAgICAgICAgICMgbWVkaWFuIGRpdmUgZHVyYXRpb24gYWxsIGRpdmVzIGNvbnNpZGVyZWQKICAgICAgICAgICAgICAgICAgICAgZGR1cmF0aW9uID0gbWVkaWFuKGRkdXJhdGlvbiwgbmEucm0gPSBUKSwKICAgICAgICAgICAgICAgICAgICAgIyBtZWRpYW4gbWF4IGRlcHRoIGFsbCBkaXZlcyBjb25zaWRlcmVkCiAgICAgICAgICAgICAgICAgICAgIG1heGRlcHRoID0gbWVkaWFuKG1heGRlcHRoLCBuYS5ybSA9IFQpLAogICAgICAgICAgICAgICAgICAgICAjIG1lZGlhbiBib3R0b20gZGl2ZXMgYWxsIGRpdmVzIGNvbnNpZGVyZWQKICAgICAgICAgICAgICAgICAgICAgYm90dHRpbWUgPSBtZWRpYW4oYm90dHRpbWUsIG5hLnJtID0gVCkKICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICBieSA9IC4oLmlkLCBkYXlfZGVwYXJ0dXJlKQpdLApvbiA9IGMoIi5pZCIsICJkYXlfZGVwYXJ0dXJlIikKXQpgYGAKCmBgYHtyLCBmaWcuY2FwPSJEcmlmdCByYXRlIHZzLiBCb3R0b20gdGltZSJ9CiMgcGxvdApnZ3Bsb3QoZGF0YVBsb3QsIGFlcyh4ID0gYm90dHRpbWUsIHkgPSBkcmlmdHJhdGUsIGNvbCA9IC5pZCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAuNSwgYWxwaGEgPSAuNSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpICsKICBndWlkZXMoY29sb3IgPSAibm9uZSIpICsKICBmYWNldF93cmFwKC5pZCB+IC4pICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCA3MDApKSArCiAgbGFicyh4ID0gIkRhaWx5IG1lZGlhbiBCb3R0b20gdGltZSAocykiLCB5ID0gIkRhaWx5IG1lZGlhbiBkcmlmdCByYXRlIChtLnMtMSkiKSArCiAgdGhlbWVfampvKCkKYGBgCgpgYGB7ciwgZmlnLmNhcD0iRHJpZnQgcmF0ZSB2cy4gTWF4aW11bSBkZXB0aCJ9CiMgcGxvdApnZ3Bsb3QoZGF0YVBsb3QsIGFlcyh4ID0gbWF4ZGVwdGgsIHkgPSBkcmlmdHJhdGUsIGNvbCA9IC5pZCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAuNSwgYWxwaGEgPSAuNSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpICsKICBndWlkZXMoY29sb3IgPSAibm9uZSIpICsKICBmYWNldF93cmFwKC5pZCB+IC4pICsKICBsYWJzKHggPSAiRGFpbHkgbWVkaWFuIE1heGltdW0gZGVwdGggKG0pIiwgeSA9ICJEYWlseSBtZWRpYW4gZHJpZnQgcmF0ZSAobS5zLTEpIikgKwogIHRoZW1lX2pqbygpCmBgYAoKYGBge3IsIGZpZy5jYXA9IkRyaWZ0IHJhdGUgdnMuIERpdmUgZHVyYXRpb24ifQojIHBsb3QKZ2dwbG90KGRhdGFQbG90LCBhZXMoeCA9IGRkdXJhdGlvbiwgeSA9IGRyaWZ0cmF0ZSwgY29sID0gLmlkKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IC41LCBhbHBoYSA9IC41KSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikgKwogIGd1aWRlcyhjb2xvciA9ICJub25lIikgKwogIGZhY2V0X3dyYXAoLmlkIH4gLikgKwogIGxhYnMoeCA9ICJEYWlseSBtZWRpYW4gRGl2ZSBkdXJhdGlvbiAocykiLCB5ID0gIkRhaWx5IG1lZGlhbiBkcmlmdCByYXRlIChtLnMtMSkiKSArCiAgdGhlbWVfampvKCkKYGBgCgojIyMgQmVoYXZpb3JhbCBBZXJvYmljIERpdmUgTGltaXQgKGJBREwpCgojIyMjIFtDb29rIGV0IGFsICgyMDA4KV0oaHR0cHM6Ly93d3cuc2NpZW5jZWRpcmVjdC5jb20vc2NpZW5jZS9hcnRpY2xlL3BpaS9TMDAwMzM0NzIwODAwMTM2WD92aWElM0RpaHViKQoKYGBge3IsIGZpZy5jYXA9IlBvc3QtZGl2ZSBkdXJhdGlvbiB2cy4gZGl2ZSBkdXJhdGlvbiJ9CiMgZGl2ZSBkdXJhdGlvbiB2cyBwZGkgYnkgZGF5cwpnZ3Bsb3QoZGF0YSA9IGRhdGFfMjAxOF9maWx0ZXJbcGRpIDwgMzAwLCBdLCBhZXMoCiAgeCA9IGRkdXJhdGlvbiwKICB5ID0gcGRpLAogIGNvbG9yID0gLmlkLAogIGdyb3VwID0gZGR1cmF0aW9uLAogIGZpbGwgPSAibm9uZSIKKSkgKwogIGdlb21fYm94cGxvdChzaG93LmxlZ2VuZCA9IEZBTFNFLCBvdXRsaWVyLmFscGhhID0gMC4wNSwgYWxwaGEgPSAwKSArCiAgbGFicyh4ID0gIkRpdmUgZHVyYXRpb24gKHMpIiwgeSA9ICJQb3N0LWRpdmUgZHVyYXRpb24gKHMpIikgKwogIGZhY2V0X3dyYXAoLiB+IC5pZCwgc2NhbGVzID0gImZyZWVfeCIpICsKICB0aGVtZV9qam8oKQpgYGAKCmBgYHtyLCBmaWcuY2FwPSJQb3N0LWRpdmUgZHVyYXRpb24gdnMuIGRpdmUgZHVyYXRpb24gKHJhdyBkYXRhKSJ9CiMgZGl2ZSBkdXJhdGlvbiB2cyBwZGkgYnkgZGF5cwpnZ3Bsb3QoZGF0YSA9IGRhdGFfMjAxOF9maWx0ZXJbcGRpIDwgMzAwLF0sIGFlcyh4ID0gZGR1cmF0aW9uLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHBkaSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gLmlkKSkgKwogIGdlb21fcG9pbnQoc2hvdy5sZWdlbmQgPSBGQUxTRSwgYWxwaGEgPSAwLjA1KSArCiAgZ2VvbV9zbW9vdGgoCiAgICBtZXRob2QgPSAiZ2FtIiwKICAgIHNob3cubGVnZW5kID0gRkFMU0UsCiAgICBjb2wgPSAiYmxhY2siLAogICAgbGluZXR5cGUgPSAiZGFzaGVkIgogICkgKwogIGxhYnMoeCA9ICJEaXZlIGR1cmF0aW9uIChzKSIsIHkgPSAiUG9zdC1kaXZlIGR1cmF0aW9uIChzKSIpICsKICBmYWNldF93cmFwKC4gfiAuaWQsIHNjYWxlcyA9ICJmcmVlX3giKSArCiAgdGhlbWVfampvKCkKYGBgCmBgYHtyLCBmaWcuY2FwPSJQb3N0LWRpdmUgZHVyYXRpb24gLyBkaXZlIGR1cmF0aW9uIHJhdGlvIHZzLiBkYXkgc2luY2UgZGVwYXJ0dXJlIn0KIyBkaXZlIGR1cmF0aW9uIHZzIHBkaSBieSBkYXlzCmdncGxvdChkYXRhID0gZGF0YV8yMDE4X2ZpbHRlcltwZGkgPCAzMDAsIC4oLmlkLCBwZGlfcmF0aW8gPSBwZGkgLyBkZHVyYXRpb24sIGRheV9kZXBhcnR1cmUpXSwgYWVzKAogIHggPSBkYXlfZGVwYXJ0dXJlLAogIHkgPSBwZGlfcmF0aW8sCiAgY29sb3IgPSAuaWQsCiAgZ3JvdXAgPSBkYXlfZGVwYXJ0dXJlLAogIGZpbGwgPSAibm9uZSIKKSkgKwogIGdlb21fYm94cGxvdChzaG93LmxlZ2VuZCA9IEZBTFNFLCBvdXRsaWVyLmFscGhhID0gMC4wNSwgYWxwaGEgPSAwKSArCiAgbGFicyh4ID0gIiMgZGF5cyBzaW5jZSBkZXBhcnR1cmUiLCB5ID0gIlBvc3QtZGl2ZSAvIERpdmUgZHVyYXRpb24gcmF0aW8iKSArCiAgZmFjZXRfd3JhcCguIH4gLmlkLCBzY2FsZXMgPSAiZnJlZV94IikgKwogICMgem9vbQogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCwwLjQpKSArCiAgdGhlbWVfampvKCkKYGBgCiMjIyMgW1NoZXJvIGV0ICphbC4qICgyMDE4KV0oaHR0cHM6Ly93d3cucmVzZWFyY2hnYXRlLm5ldC9wdWJsaWNhdGlvbi8yMjI2ODMwNDJfVG9fYnJlYXRoZV9vcl9ub3RfdG9fYnJlYXRoZV9PcHRpbWFsX2JyZWF0aGluZ19hZXJvYmljX2RpdmVfbGltaXRfYW5kX294eWdlbl9zdG9yZXNfaW5fZGVlcC1kaXZpbmdfYmx1ZS1leWVkX3NoYWdzKQoKQmFzZWQgb24gW1NoZXJvIGV0ICphbC4qICgyMDE4KV0oaHR0cHM6Ly93d3cucmVzZWFyY2hnYXRlLm5ldC9wdWJsaWNhdGlvbi8yMjI2ODMwNDJfVG9fYnJlYXRoZV9vcl9ub3RfdG9fYnJlYXRoZV9PcHRpbWFsX2JyZWF0aGluZ19hZXJvYmljX2RpdmVfbGltaXRfYW5kX294eWdlbl9zdG9yZXNfaW5fZGVlcC1kaXZpbmdfYmx1ZS1leWVkX3NoYWdzKSwgd2UgZGVjaWRlZCB0byBsb29rIGF0IHRoZSAqYkFETCogYXMgdGhlIDk1dGggcGVyY2VudGlsZSBvZiBkaXZlIGR1cmF0aW9uIGVhY2ggZGF5LCBmb3IgdGhvc2Ugd2l0aCAkbiBcZ2VxIDUwJC4gVGhpcyB0aHJlc2hvbGQgd2FzIGNob3NlbiBmb2xsb3dpbmcgdGhpcyBmaWd1cmU6CgpgYGB7ciwgZmlnLmNhcD0iRGlzdHJpYnV0aW9uIG9mIHRoZSBudW1iZXIgb2YgZGl2ZXMgZWFjaCBkYXkuIFRoZSB0aHJlc2hvbGQgdXNlZCB0byBjYWxjdWxhdGUgYkFETCBpcyBmaXhlZCBhdCA1MCBkaXZlcyBwZXIgZGF5LiIsIGZpZy5oZWlnaHQ9M30KZ2dwbG90KGRhdGFfMjAxOF9maWx0ZXJbLC4obmJfZGl2ZXMgPSAuTiksIAogICAgICAgICAgICAgICAgICAgICAgICBieSA9IC4oLmlkLCBkYXlfZGVwYXJ0dXJlKV0sIAogICAgICAgYWVzKHg9bmJfZGl2ZXMsIGZpbGw9LmlkKSkgKwogIGdlb21faGlzdG9ncmFtKHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgZmFjZXRfZ3JpZCgufi5pZCkgKwogIGxhYnMoeT0iIyBvZiBkYXlzIiwgeCA9ICIjIG9mIGRpdmVzIHBlciBkYXkiKSArCiAgdGhlbWVfampvKCkKYGBgCgpgYGB7ciwgZmlnLmNhcD0iQmVoYXZpb3JhbCBBREwgdnMuIGRyaWZ0IHJhdGUgYWxvbmcgYW5pbWFscycgdHJpcCAoQW0gSSB0aGUgb25seSBvbmUgc2VlaW5nIHNvbWUga2luZCBvZiByZWxhdGlvbnNoaXA/KSJ9CiMgc2VsZWN0IGRheSB0aGF0IGhhdmUgYXQgbGVhc3QgNTAgZGl2ZXMKZGF5c190b19rZWVwID0gZGF0YV8yMDE4X2ZpbHRlclssCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLihuYl9kaXZlcyA9IC5OKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IC4oLmlkLCBkYXlfZGVwYXJ0dXJlKV0gJT4lCiAgLltuYl9kaXZlcyA+PSA1MCxdCgojIGtlZXAgb25seSB0aG9zZSBkYXlzCmRhdGFfMjAxOF9maWx0ZXJfY29tcGxldGVfZGF5ID0gbWVyZ2UoZGF0YV8yMDE4X2ZpbHRlciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3RvX2tlZXAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBjKCIuaWQiLCAiZGF5X2RlcGFydHVyZSIpKQoKIyBkYXRhIHBsb3QKZGF0YVBsb3QgPSBkYXRhXzIwMThfZmlsdGVyX2NvbXBsZXRlX2RheVssCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLihiYWRsID0gcXVhbnRpbGUoZGR1cmF0aW9uLCAwLjk1KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAuKC5pZCwgZGF5X2RlcGFydHVyZSldCgojIGNvbWJpbmUgdHdvIGRhdGFzZXRzIHRvIGJlIGFibGUgdG8gdXNlIGEgc2Vjb25kIGF4aXMKIyBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy80OTE4NTU4My90d28teS1heGVzLXdpdGgtZGlmZmVyZW50LXNjYWxlcy1mb3ItdHdvLWRhdGFzZXRzLWluLWdncGxvdDIKZGF0YU1lZ2FQbG90ID0gcmJpbmQoZGF0YV8yMDE4X2ZpbHRlcl9jb21wbGV0ZV9kYXlbZGl2ZXR5cGUgPT0gIjI6IGRyaWZ0Il0gJT4lCiAgICAgICAgICAgICAgICAgICAgICAgLlssIC4odyA9IC5pZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gZHJpZnRyYXRlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSBkYXlfZGVwYXJ0dXJlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHogPSAic2Vjb25kX3Bsb3QiKV0sCiAgICAgICAgICAgICAgICAgICAgIGRhdGFQbG90WywgLigKICAgICAgICAgICAgICAgICAgICAgICB3ID0gLmlkLAogICAgICAgICAgICAgICAgICAgICAgICMgdHJpY2t5IG9uZQogICAgICAgICAgICAgICAgICAgICAgIHkgPSAoYmFkbCAvIDEwMDApIC0gMSwKICAgICAgICAgICAgICAgICAgICAgICB4ID0gZGF5X2RlcGFydHVyZSwKICAgICAgICAgICAgICAgICAgICAgICB6ID0gImZpcnN0X3Bsb3QiCiAgICAgICAgICAgICAgICAgICAgICldKQoKIyBwbG90CmdncGxvdCgpICsKICBnZW9tX3BvaW50KAogICAgZGF0YSA9IGRhdGFNZWdhUGxvdFt6ID09ICJzZWNvbmRfcGxvdCIsIF0sCiAgICBhZXMoeCA9IHgsIHkgPSB5KSwKICAgIGFscGhhID0gMSAvIDEwLAogICAgc2l6ZSA9IDAuNSwKICAgIGNvbG9yID0gImdyZXk0MCIsCiAgICBzaG93LmxlZ2VuZCA9IEZBTFNFCiAgKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBkYXRhTWVnYVBsb3RbeiA9PSAiZmlyc3RfcGxvdCIsIF0sCiAgICAgICAgICAgIGFlcyh4ID0geCwgeSA9IHksIGNvbG9yID0gdyksCiAgICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoCiAgICAjIEZlYXR1cmVzIG9mIHRoZSBmaXJzdCBheGlzCiAgICBuYW1lID0gIkRyaWZ0IHJhdGUgKG0vcykiLAogICAgIyBBZGQgYSBzZWNvbmQgYXhpcyBhbmQgc3BlY2lmeSBpdHMgZmVhdHVyZXMKICAgIHNlYy5heGlzID0gc2VjX2F4aXMoIH4gKC4gKiAxMDAwKSArIDEwMDAsIG5hbWUgPSAiQmVoYXZpb3JhbCBBZXJvYmljIERpdmUgTGltaXQgKHMpIikKICApICsKICBsYWJzKHggPSAiIyBkYXlzIHNpbmNlIGRlcGFydHVyZSIpICsKICBmYWNldF93cmFwKHcgfiAuKSArCiAgdGhlbWVfampvKCkKYGBgCgo+IExvb2tpbmcgYXQgdGhpcyBncmFwaCwgSSB3YW50IHRvIGJlbGlldmUgdGhhdCB0aGVyZSBpcyBzb21lIGtpbmQgb2YgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlICpiQURMKiBhcyBkZWZpbmVkIGJ5IFtTaGVybyBldCAqYWwuKiAoMjAxOCldKGh0dHBzOi8vd3d3LnJlc2VhcmNoZ2F0ZS5uZXQvcHVibGljYXRpb24vMjIyNjgzMDQyX1RvX2JyZWF0aGVfb3Jfbm90X3RvX2JyZWF0aGVfT3B0aW1hbF9icmVhdGhpbmdfYWVyb2JpY19kaXZlX2xpbWl0X2FuZF9veHlnZW5fc3RvcmVzX2luX2RlZXAtZGl2aW5nX2JsdWUtZXllZF9zaGFncykgYW5kIHRoZSBkcmlmdCByYXRlIChhbmQgc28gYnV5b2FuY3kpLgoKYGBge3J9CiMgZ2V0IGJhZGwKZGF0YXBsb3RfMSA9IGRhdGFfMjAxOF9maWx0ZXJfY29tcGxldGVfZGF5WywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLihiYWRsID0gcXVhbnRpbGUoZGR1cmF0aW9uLCAwLjk1KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gLiguaWQsIGRheV9kZXBhcnR1cmUpXQojIGdldCBkcmlmdHJhdGUKZGF0YXBsb3RfMiA9IGRhdGFfMjAxOF9maWx0ZXJfY29tcGxldGVfZGF5W2RpdmV0eXBlID09ICIyOiBkcmlmdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4oZHJpZnRyYXRlID0gbWVkaWFuKGRyaWZ0cmF0ZSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IC4oLmlkLCBkYXlfZGVwYXJ0dXJlKV0KCiMgbWVyZ2UKZGF0YVBsb3QgPSBtZXJnZShkYXRhcGxvdF8xLAogICAgICAgICAgICAgICAgIGRhdGFwbG90XzIsCiAgICAgICAgICAgICAgICAgYnkgPSBjKCIuaWQiLCAiZGF5X2RlcGFydHVyZSIpLAogICAgICAgICAgICAgICAgIGFsbCA9IFRSVUUpCgojIHBsb3QKZ2dwbG90KGRhdGEgPSBkYXRhUGxvdCwgYWVzKHggPSBiYWRsLCB5ID0gZHJpZnRyYXRlLCBjb2wgPSAuaWQpKSArCiAgZ2VvbV9wb2ludChzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZmFjZXRfd3JhcCguaWR+Liwgc2NhbGVzID0gImZyZWUiKSArCiAgdGhlbWVfampvKCkKYGBgCgojIyMjIHsudW5saXN0ZWQgLnVubnVtYmVyZWQgLnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30KCiMjIyMjIGluZF8yMDE4MDcwIHsudW5saXN0ZWQgLnVubnVtYmVyZWR9CgpgYGB7cn0KIyBpbmRfMjAxODA3MApwbG90X2x5KAogIHggPSBkYXRhUGxvdFsuaWQgPT0gImluZF8yMDE4MDcwIiwgYmFkbF0sCiAgeSA9IGRhdGFQbG90Wy5pZCA9PSAiaW5kXzIwMTgwNzAiLCBkYXlfZGVwYXJ0dXJlXSwKICB6ID0gZGF0YVBsb3RbLmlkID09ICJpbmRfMjAxODA3MCIsIGRyaWZ0cmF0ZV0sCiAgdHlwZSA9ICJzY2F0dGVyM2QiLAogIG1vZGUgPSAibWFya2VycyIsCiAgbWFya2VyID0gbGlzdChzaXplID0gMiksCiAgY29sb3IgPSBkYXRhUGxvdFsuaWQgPT0gImluZF8yMDE4MDcwIiwgZGF5X2RlcGFydHVyZV0KKSAlPiUgCiAgbGF5b3V0KHNjZW5lID0gbGlzdCh4YXhpcyA9IGxpc3QodGl0bGUgPSAnQmVoYXZpb3JhbCBBREwnKSwKICAgICAgICAgICAgICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICcjIGRheXMgc2luY2UgZGVwYXJ0dXJlJyksCiAgICAgICAgICAgICAgICAgICAgICB6YXhpcyA9IGxpc3QodGl0bGUgPSAnRHJpZnQgcmF0ZSAobS9zKScpKSkKYGBgCiMjIyMjIGluZF8yMDE4MDcyIHsudW5saXN0ZWQgLnVubnVtYmVyZWR9CgpgYGB7cn0KIyBpbmRfMjAxODA3MgpwbG90X2x5KAogIHggPSBkYXRhUGxvdFsuaWQgPT0gImluZF8yMDE4MDcyIiwgYmFkbF0sCiAgeSA9IGRhdGFQbG90Wy5pZCA9PSAiaW5kXzIwMTgwNzIiLCBkYXlfZGVwYXJ0dXJlXSwKICB6ID0gZGF0YVBsb3RbLmlkID09ICJpbmRfMjAxODA3MiIsIGRyaWZ0cmF0ZV0sCiAgdHlwZSA9ICJzY2F0dGVyM2QiLAogIG1vZGUgPSAibWFya2VycyIsCiAgbWFya2VyID0gbGlzdChzaXplID0gMiksCiAgY29sb3IgPSBkYXRhUGxvdFsuaWQgPT0gImluZF8yMDE4MDcyIiwgZGF5X2RlcGFydHVyZV0KKSAlPiUgCiAgbGF5b3V0KHNjZW5lID0gbGlzdCh4YXhpcyA9IGxpc3QodGl0bGUgPSAnQmVoYXZpb3JhbCBBREwnKSwKICAgICAgICAgICAgICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICcjIGRheXMgc2luY2UgZGVwYXJ0dXJlJyksCiAgICAgICAgICAgICAgICAgICAgICB6YXhpcyA9IGxpc3QodGl0bGUgPSAnRHJpZnQgcmF0ZSAobS9zKScpKSkKYGBgCgojIyMjIyBpbmRfMjAxODA3NCB7LnVubGlzdGVkIC51bm51bWJlcmVkfQoKYGBge3J9CiMgaW5kXzIwMTgwNzQKcGxvdF9seSgKICB4ID0gZGF0YVBsb3RbLmlkID09ICJpbmRfMjAxODA3NCIsIGJhZGxdLAogIHkgPSBkYXRhUGxvdFsuaWQgPT0gImluZF8yMDE4MDc0IiwgZGF5X2RlcGFydHVyZV0sCiAgeiA9IGRhdGFQbG90Wy5pZCA9PSAiaW5kXzIwMTgwNzQiLCBkcmlmdHJhdGVdLAogIHR5cGUgPSAic2NhdHRlcjNkIiwKICBtb2RlID0gIm1hcmtlcnMiLAogIG1hcmtlciA9IGxpc3Qoc2l6ZSA9IDIpLAogIGNvbG9yID0gZGF0YVBsb3RbLmlkID09ICJpbmRfMjAxODA3NCIsIGRheV9kZXBhcnR1cmVdCikgJT4lIAogIGxheW91dChzY2VuZSA9IGxpc3QoeGF4aXMgPSBsaXN0KHRpdGxlID0gJ0JlaGF2aW9yYWwgQURMJyksCiAgICAgICAgICAgICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAnIyBkYXlzIHNpbmNlIGRlcGFydHVyZScpLAogICAgICAgICAgICAgICAgICAgICAgemF4aXMgPSBsaXN0KHRpdGxlID0gJ0RyaWZ0IHJhdGUgKG0vcyknKSkpCmBgYAoKIyMjIyMgaW5kXzIwMTgwNzIgey51bmxpc3RlZCAudW5udW1iZXJlZH0KCmBgYHtyfQojIGluZF8yMDE4MDgwCnBsb3RfbHkoCiAgeCA9IGRhdGFQbG90Wy5pZCA9PSAiaW5kXzIwMTgwODAiLCBiYWRsXSwKICB5ID0gZGF0YVBsb3RbLmlkID09ICJpbmRfMjAxODA4MCIsIGRheV9kZXBhcnR1cmVdLAogIHogPSBkYXRhUGxvdFsuaWQgPT0gImluZF8yMDE4MDgwIiwgZHJpZnRyYXRlXSwKICB0eXBlID0gInNjYXR0ZXIzZCIsCiAgbW9kZSA9ICJtYXJrZXJzIiwKICBtYXJrZXIgPSBsaXN0KHNpemUgPSAyKSwKICBjb2xvciA9IGRhdGFQbG90Wy5pZCA9PSAiaW5kXzIwMTgwODAiLCBkYXlfZGVwYXJ0dXJlXQopICU+JSAKICBsYXlvdXQoc2NlbmUgPSBsaXN0KHhheGlzID0gbGlzdCh0aXRsZSA9ICdCZWhhdmlvcmFsIEFETCcpLAogICAgICAgICAgICAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gJyMgZGF5cyBzaW5jZSBkZXBhcnR1cmUnKSwKICAgICAgICAgICAgICAgICAgICAgIHpheGlzID0gbGlzdCh0aXRsZSA9ICdEcmlmdCByYXRlIChtL3MpJykpKQpgYGAKCiMjIyBHUFMgZGF0YQoKYGBge3IsIGZpZy5jYXA9Ik1hcCB3aXRoIHBvbHlsaW5lcyIsIGZpZy53aWR0aD04LCBldmFsPUZBTFNFfQojIFRoaXMgcGllY2Ugb2YgY29kZSBpcyBvbmx5IHRoZXJlIHRvIHNob3cgaG93IHRvIGRyYXcgYSBwb2x5bGluZXMgd2l0aCBhIGdyYWRpZW50IGNvbG9yIHVzaW5nIGxlYWZsZXQuCiMgV2UncmUgbm90IHVzaW5nIGl0IGR1ZSB0byB0aGUgc2l6ZSBvZiB0aGUgY3JlYXRlZCBtYXAsIGFuZCB3aWxsIGNvbnRpbnVlIHVzaW5nIGNpcmNsZSBtYXJrZXIKCiMgZGF0YXNldHMgdXNlZCB0byBkaXNwbGF5IG1hcApkZl9kcmlmdHJhdGUgPSB1bmlxdWUoZGF0YV8yMDE4X2ZpbHRlclsuaWQgPT0gImluZF8yMDE4MDcwIiAmIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpdmV0eXBlID09ICIyOiBkcmlmdCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuKC5pZCwgbGF0LCBsb24sIGRkdXJhdGlvbildKQoKIyBjb2xvciBwYWxldHRlCnBhbCA8LSBjb2xvck51bWVyaWMoCiAgcGFsZXR0ZSA9ICJZbEduQnUiLAogIGRvbWFpbiA9IGRmX2RyaWZ0cmF0ZSRkZHVyYXRpb24KKQoKIyBhZGQgCmRmX2RyaWZ0cmF0ZVssIGA6PWAobmV4dExhdCA9IHNoaWZ0KGxhdCksCiAgICAgICAgICAgICAgICAgICAgbmV4dExvbiA9IHNoaWZ0KGxvbiksCiAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBwYWwoZGZfZHJpZnRyYXRlJGRkdXJhdGlvbikpXQoKIyBpbnRlcmFjdGl2ZSBtYXAKZ3JhZGllbnRfbWFwIDwtIGxlYWZsZXQoKSAlPiUKICBzZXRWaWV3KGxuZyA9IC0xMjIsIGxhdCA9IDM4LCB6b29tID0gMikgJT4lCiAgYWRkVGlsZXMoKSAKCiMgYWRkIGxpbmVzCmZvciAoaSBpbiAxOm5yb3coZGZfZHJpZnRyYXRlKSkgewogIGdyYWRpZW50X21hcCA8LSBhZGRQb2x5bGluZXMoCiAgICBtYXAgPSBncmFkaWVudF9tYXAsCiAgICBkYXRhID0gZGZfZHJpZnRyYXRlLAogICAgbGF0ID0gYXMubnVtZXJpYyhkZl9kcmlmdHJhdGVbaSwgYygnbGF0JywgJ25leHRMYXQnKV0pLAogICAgbG5nID0gYXMubnVtZXJpYyhkZl9kcmlmdHJhdGVbaSwgYygnbG9uJywgJ25leHRMb24nKV0pLAogICAgY29sb3IgPSBkZl9kcmlmdHJhdGVbaSwgY29sb3JdLAogICAgd2VpZ2h0ID0gMywKICAgIGdyb3VwID0gImluZGl2aWR1YWxfMSIKICApCn0KCiMgYWRkIGxheWVyIGNvbnRyb2wKZ3JhZGllbnRfbWFwIDwtIGFkZExheWVyc0NvbnRyb2woCiAgbWFwID0gZ3JhZGllbnRfbWFwLAogIG92ZXJsYXlHcm91cHMgPSBjKCJpbmRpdmlkdWFsXzEiKSwKICBvcHRpb25zID0gbGF5ZXJzQ29udHJvbE9wdGlvbnMoY29sbGFwc2VkID0gRkFMU0UpCikKCiMgZm9ybWF0KG9iamVjdC5zaXplKGdyYWRpZW50X21hcCksIHVuaXRzID0gIk1iIikKYGBgCgpCZWNhdXNlIGZvciBzb21lIGRhdGEgdGhlIGNvbnRyYXN0IGluIGNoYW5nZXMgd2FzIG5vdCBlbm91Z2ggbWFya2VkLCB0aGUgb25seSB0cmVhdG1lbnQgYXBwbGllZCBvbiB0aGVzZSBkYXRhIGlzIHRvIHJlbW92ZSBvdXRsaWVycyBmb3IgZWFjaCB2YXJpYWJsZSB1c2luZyB0aGUgaW50ZXJxdWFydGlsZSByYW5nZSBydWxlLiAKCmBgYHtyfQojIGludGVyYWN0aXZlIG1hcApncmFkaWVudF9tYXAgPC0gbGVhZmxldCgpICU+JQogIHNldFZpZXcobG5nID0gLTEzMiwgbGF0ID0gNDgsIHpvb20gPSA0KSAlPiUKICBhZGRUaWxlcygpCgojIGxvb3AgYnkgaW5kaXZpZHVhbHMgYW5kIHZhcmlhYmxlCmdycHMgPSBOVUxMCmZvciAoaSBpbiBzZXEoZGF0YV8yMDE4X2ZpbHRlclshaXMubmEobGF0KSx1bmlxdWUoLmlkKV0pKXsKICBmb3IgKGsgaW4gYygiZGR1cmF0aW9uIiwibWF4ZGVwdGgiLCJlZmZpY2llbmN5IiwgImRyaWZ0cmF0ZSIpKXsKICAgIGlmIChrID09ICJkcmlmdHJhdGUiKXsKICAgICAgIyBzZXQgZGF0YXNldCB1c2VkIHRvIHBsb3QKICAgICAgZGF0YVBsb3QgPSB1bmlxdWUoZGF0YV8yMDE4X2ZpbHRlciAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgLltvcmRlcihkYXRlKSxdICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAuWy5pZD09ZGF0YV8yMDE4X2ZpbHRlclshaXMubmEobGF0KSwgdW5pcXVlKC5pZCldW2ldICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGl2ZXR5cGUgPT0gIjI6IGRyaWZ0IiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICFpcy5uYShnZXQoaykpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoImxhdCIsICJsb24iLCBrKSwgd2l0aD1GQUxTRV0gJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgIC5bIWlzX291dGxpZXIoZ2V0KGspKSxdKQogICAgICAjIGNvbG9yIHBhbGV0dGUgY3JlYXRpb24KICAgICAgY29sUGFsIDwtIGNvbG9yTnVtZXJpYygKICAgICAgICBwYWxldHRlID0gIkJyQkciLAogICAgICAgIGRvbWFpbiA9IHNlcSgtZGF0YVBsb3RbLG1heChhYnMoZHJpZnRyYXRlKSldLAogICAgICAgICAgICAgICAgICAgICBkYXRhUGxvdFssbWF4KGFicyhkcmlmdHJhdGUpKV0sCiAgICAgICAgICAgICAgICAgICAgIDAuMSkKICAgICAgKQogICAgfSBlbHNlIHsKICAgICAgIyBzZXQgZGF0YXNldCB1c2VkIHRvIHBsb3QKICAgICAgZGF0YVBsb3QgPSB1bmlxdWUoZGF0YV8yMDE4X2ZpbHRlciAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgLltvcmRlcihkYXRlKSxdICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAuWy5pZD09ZGF0YV8yMDE4X2ZpbHRlclshaXMubmEobGF0KSwgdW5pcXVlKC5pZCldW2ldICYgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpdmV0eXBlICE9ICIyOiBkcmlmdCIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAhaXMubmEoZ2V0KGspKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCJsYXQiLCAibG9uIiwgayksIHdpdGg9RkFMU0VdICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAuWyFpc19vdXRsaWVyKGdldChrKSksXSkgCiAgICAgICMgY29sb3IgcGFsZXR0ZSBjcmVhdGlvbgogICAgICBjb2xQYWwgPC0gY29sb3JOdW1lcmljKAogICAgICAgIHBhbGV0dGUgPSAiWWxHbkJ1IiwKICAgICAgICBkb21haW4gPSBkYXRhUGxvdFssZ2V0KGspXQogICAgICApCiAgICB9CiAgICAKICAgICMgYWRkIGNvbG9yIHRvIGRhdGFzZXQKICAgIGRhdGFQbG90WywgY29sb3IgOj0gY29sUGFsKGRhdGFQbG90WyxnZXQoayldKV0KICAgICMgYWRkIHNpemUgY29sdW1uCiAgICBkYXRhUGxvdFssIHJhZGl1cyA6PSAzXQogICAgIyBtYXJrIHRoZSBiZWdpbm5pbmcgb2YgdGhlIHRyaXAKICAgIGRhdGFQbG90WzEsIGA6PWAgKGNvbG9yID0gImdyZWVuIiwKICAgICAgICAgICAgICAgICAgICAgIHJhZGl1cyA9IDQpXQogICAgIyBtYXJrIHRoZSBlbmQgb2YgdGhlIHRyaXAKICAgIGRhdGFQbG90Wy5OLCBgOj1gIChjb2xvciA9ICJyZWQiLAogICAgICAgICAgICAgICAgICAgICAgIHJhZGl1cyA9IDQpXQogICAgIyByZW9yZGVyIHRvIG1ha2UgdGhlIGVuZCBhbmQgdGhlIGJlZ2lubmluZyBpbiBmcm9udAogICAgZGF0YVBsb3QgPSByYmluZChkYXRhUGxvdFstMSxdLGRhdGFQbG90WzEsXSkKICAgICMgYWRkIG1hcmtlcnMgdG8gbWFwCiAgICBncmFkaWVudF9tYXAgPC0gYWRkQ2lyY2xlTWFya2VycygKICAgICAgbWFwID0gZ3JhZGllbnRfbWFwLAogICAgICBkYXRhID0gZGF0YVBsb3QsCiAgICAgIGxhdCA9IH5sYXQsCiAgICAgIGxuZyA9IH5sb24sCiAgICAgIHJhZGl1cyA9IH5yYWRpdXMsCiAgICAgIHN0cm9rZSA9IEZBTFNFLAogICAgICBjb2xvciA9IH5jb2xvciwKICAgICAgZmlsbE9wYWNpdHkgPSAxLAogICAgICBncm91cCA9IHBhc3RlKGRhdGFfMjAxOF9maWx0ZXJbLHVuaXF1ZSguaWQpXVtpXSwgIi0iLCBrKQogICAgKSAlPiUgCiAgICAgIGFkZExlZ2VuZCgiYm90dG9tbGVmdCIsIAogICAgICAgICAgICAgICAgZGF0YSA9IGRhdGFQbG90LAogICAgICAgICAgICAgICAgZ3JvdXAgPSBwYXN0ZShkYXRhXzIwMThfZmlsdGVyWyx1bmlxdWUoLmlkKV1baV0sICItIiwgayksCiAgICAgICAgICAgICAgICBwYWwgPSBjb2xQYWwsIAogICAgICAgICAgICAgICAgdmFsdWVzID0gfmdldChrKSwKICAgICAgICAgICAgICAgIHRpdGxlID0gaywKICAgICAgICAgICAgICAgIG9wYWNpdHkgPSAxCiAgICAgICkKICAgICMgcmV0cmlldmUgZ3JvdXBzCiAgICBncnBzID0gYyhncnBzLCBwYXN0ZShkYXRhXzIwMThfZmlsdGVyWyx1bmlxdWUoLmlkKV1baV0sICItIiwgaykpCiAgfQp9CgojIGFkZCBsYXllciBjb250cm9sCmdyYWRpZW50X21hcCA8LSBhZGRMYXllcnNDb250cm9sKAogIG1hcCA9IGdyYWRpZW50X21hcCwKICBvdmVybGF5R3JvdXBzID0gZ3JwcywKICBvcHRpb25zID0gbGF5ZXJzQ29udHJvbE9wdGlvbnMoY29sbGFwc2VkID0gVFJVRSkKKSAlPiUgaGlkZUdyb3VwKGdycHMpCmBgYAoKYGBge3IsIGZpZy5jYXA9IlRyYWNraW5nIGRhdGEgMjAxOCBpbmRpdmlkdWFscyAoZ3JlZW4gYW5kIHJlZCBkb3QgcmVzcGVjdGl2ZWx5IGluZGljYXRlIHRoZSBiZWdpbm5pbmcgYW5kIHRoZSBlbmQgb2YgZWFjaCB0cmlwKSIsIGZpZy53aWR0aD04fQojIGRpc3BsYXkKZ3JhZGllbnRfbWFwCmBgYAoK